第2章 Zend_Cache

目次

2.1. 導入
2.2. キャッシュの仕組み
2.2.1. Zend_Cache ファクトリメソッド
2.2.2. レコードのタグ付け
2.2.3. キャッシュの削除
2.3. Zend_Cache のフロントエンド
2.3.1. Zend_Cache_Core
2.3.2. Zend_Cache_Frontend_Output
2.3.3. Zend_Cache_Frontend_Function
2.3.4. Zend_Cache_Frontend_Class
2.3.5. Zend_Cache_Frontend_File
2.3.6. Zend_Cache_Frontend_Page
2.4. Zend_Cache のバックエンド
2.4.1. Zend_Cache_Backend_File
2.4.2. Zend_Cache_Backend_Sqlite
2.4.3. Zend_Cache_Backend_Memcached
2.4.4. Zend_Cache_Backend_APC

2.1. 導入

Zend_Cache は、任意のデータをキャッシュするための一般的な手法を提供します。

Zend Framework におけるキャッシュ処理はフロントエンドで行われ、キャッシュレコードの保存には バックエンドのアダプタ (FileSqliteMemcache...) を使用します。ID およびタグを使用した柔軟な仕組みが用いられています。これらを使用することで、 キャッシュデータの一部だけを削除する (「指定したタグがつけられているキャッシュレコードをすべて削除する」 など) といったことも簡単にできるようになります。

このモジュールの中心となる部分 (Zend_Cache_Core) は、標準的で柔軟なものとなっています。 設定変更も可能です。とは言え、 特定の目的のためには、より適切な実行結果を得るためのフロントエンド Zend_Cache_Core を拡張する (たとえば OutputFileFunctionClass など) こともできます。

例 2.1. Zend_Cache::factory() によるフロントエンドの取得

Zend_Cache::factory() は、適切なオブジェクトを作成してそれらを互いに結び付けます。 この最初の例では、フロントエンドに Core、バックエンドに File を使用します。

<?php
require_once 'Zend/Cache.php';

$frontendOptions = array(
   'lifeTime' => 7200, // キャッシュの有効期限を 2 時間とします
   'automaticSerialization' => true
);

$backendOptions = array(
    'cacheDir' => './tmp/' // キャッシュファイルを書き込むディレクトリ
);

// Zend_Cache_Core オブジェクトを取得します
$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);

?>

これでフロントエンドが得られました。あらゆる種類のデータを保存することができます (そのために、シリアライズを有効にしました)。例えば、非常に時間がかかるデータベースクエリの結果を キャッシュすることが可能です。いったんキャッシュしてしまえば、 あとはデータベースに接続する必要さえありません。キャッシュから取得したレコードを アンシリアライズしてデータを取得すればよいのです。

<?php

// $cache は先ほどの例で作成したものです

// キャッシュがすでに存在するかどうかを調べます
if(!$result = $cache->get('myresult')) {

    // キャッシュが見つかりませんでした。データベースに接続します
    
    $db = Zend_Db::factory( [...] );
    
    $result = $db->fetchAll('SELECT * FROM huge_table');
    
    $cache->save($result, 'myresult');
    
} else {

    // キャッシュが見つかりました! 大声で叫びましょう
    echo "これはキャッシュからのデータです!\n\n";
    
}

print_r($result);

?>

例 2.2. Zend_Cache 出力フロントエンドによる出力のキャッシュ

まず、出力をキャッシュしたい部分を何らかの条件式で「マークアップ」し、 その前後を start() メソッドおよび end() メソッドで囲みます (これは最初の例に似ており、キャッシュ処理の基本となる考え方です)。

内部では、通常通りに出力を行います。出力内容は、 end() メソッドに到達するまでずっとキャッシュされます。次回の実行時には、 このセクションが読み飛ばされ、その代わりにキャッシュから取得したデータが使用されます (キャッシュレコードが有効なものである限ります)。

<?php

$frontendOptions = array(
   'lifeTime' => 30,                  // キャッシュの有効期間は 30 秒です
   'automaticSerialization' => false  // これはデフォルト値です
);n

$backendOptions = array('cacheDir' => './tmp/');

$cache = Zend_Cache::factory('Output', 'File', $frontendOptions, $backendOptions);

// start() メソッドに一意な ID を渡します
if(!$cache->start('mypage')) {
    // 通常通りに出力します
    
    echo 'Hello world! ';
    echo 'これはキャッシュされます ('.time().') ';
    
    $cache->end(); // 出力が保存され、ブラウザに送信されます
}

echo 'これはキャッシュされません ('.time().').';

?>       

time() の結果を二度出力していることに注目しましょう。 動作説明のため、何らかの動的な出力がほしかったのです。これを実行し、 さらに何度か「最新の情報に更新」してみましょう。 ふたつめの値が時とともに変化していくのに対して、 最初の方の値は変化しないことに気づかれるでしょう。 なぜなら、最初の値はキャッシュされたセクションの出力であり、 その他の内容とともにキャッシュに保存されているからです。 30 秒経過すると (有効期限を 30 秒に設定したので)、 ふたつの値は再び一致するようになります。これはキャッシュレコードが 有効期限切れになり、もう一度キャッシュしなおされたからです。 この例は、ブラウザあるいはコンソールで試してみてください。

[注意] 注意

Zend_Cache を使用する際には、キャッシュ ID (save() および start() で使用します) に十分な注意を払うようにしましょう。 これは、キャッシュしようとしているリソース内で一意である必要があります。 さもないと、無関係なレコードによってキャッシュを削除されてしまったり、 さらに悪いことにはまったく無関係な場所に表示されてしまったりなどという問題が起こります。