[CodeIgniter2.x]Cacheの利用について


CodeIgniter 1.xの頃のキャッシュというとページキャッシュでしたが、CodeIgntier2からMemcache等を利用できるようになり、ページキャッシュだけでなく、オブジェクトのキャッシュも利用可能になりました。ということで、Cacheの利用について少し書きたいと思います。結果から言えば、なかなか使いやすいものでした。

利用可能なキャッシュの種類

現在、CodeIgniter 2.0.1でサポートしているキャッシュは以下の4種類です。

  • File: ローカルのファイルをキャッシュとして利用します。
  • APC: PHPアクセラレータであるAPCのキャッシュ機能を利用します。
  • Memcache: PHPだと一番利用率が高いのではないかと思われるMemcachedを利用します。
  • Dummy: 開発用のダミーで実際には何もキャッシュしません。

広告

登場人物

system/libraries/Cache/drivers/

最初に述べた4種類のキャッシュについての実装がそれぞれ含まれています。

system/libraries/Cache/Cache.php

Cache/drivers/の各実装のCacheのインタフェースです。ここを見れば、キャッシュでどういう行動(登録、取得、削除など)が出来るかわかると思います。

system/libraries/Driver#CI_Driverクラス

CI_Driverを継承したサブクラスから__get, __set, __callが呼ばれた場合、親クラス、今回の場合だと、Cacheクラスにアクセスする機能を付与する。(CI_Driver#decorate)

system/libraries/Driver#CI_Driver_Libraryクラス

CI_Driver_Libraryを継承するクラスから__getが呼ばれた場合に、valid_driversに基づき指定されたクラスのインスタンスを生成する。Factory的な振る舞いをする。

設定ファイル

application/config/cache.php

cacheの基本的な設定を記述します。adapterはfile、apc、memcached、dummyのいずれかを指定します。

< ?php
$config = array(
        'adapter' => 'memcached',
);

application/config/memcached.php

上記のcache.phpでmemcachedを指定した場合に、system/libraries/Cache/drivers/Cache_memcached.phpの初期化パラメータを指定します。$config変数に連想配列形式でキャッシュサーバの識別子と設定情報を記述します。下記の例ではcache1、cache2を指定していますが、もちろん一つでも問題ありません。

< ?php
$config = array (
        'cache1' => array(
                'hostname' => '127.0.0.1',
                'port' => 11211,
                'weight' => 1,
        ),
        'cache2' => array(
                'hostname' => '127.0.0.1',
                'port' => 11212,
                'weight' => 1,
        ),
);

ちなみにmemcachedを指定してmemcached.phpを作成しなかった場合、正常に動作しませんので注意してください。これは、実装バグだと思われます。具体的には、system/libraries/Cache/drivers/Cache_memcached.phpの下記の部分に現れる$this->_default_optionsというフィールドの設定が一度も初期化されていない為です。

        /**
         * Setup memcached.
         */
        private function _setup_memcached()
        {
                // Try to load memcached server info from the config file.
                $CI =& get_instance();
                if ($CI->config->load('memcached', TRUE, TRUE))
                {
                        if (is_array($CI->config->config['memcached']))
                        {
                                $this->_memcache_conf = NULL;
 
                                foreach ($CI->config->config['memcached'] as $name => $conf)
                                {
                                        $this->_memcache_conf[$name] = $conf;
                                }                               
                        }                       
                }
 
                $this->_memcached = new Memcached();
 
                foreach ($this->_memcache_conf as $name => $cache_server)
                {
                        if ( ! array_key_exists('hostname', $cache_server))
                        {
                                $cache_server['hostname'] = $this->_default_options['default_host'];
                        }
 
                        if ( ! array_key_exists('port', $cache_server))
                        {
                                $cache_server['port'] = $this->_default_options['default_port'];
                        }
 
                        if ( ! array_key_exists('weight', $cache_server))
                        {
                                $cache_server['weight'] = $this->_default_options['default_weight'];
                        }
 
                        $this->_memcached->addServer(
                                        $cache_server['hostname'], $cache_server['port'], $cache_server['weight']
                        );
                }
        }

説明が長くなりましたが、実際にコントローラなどで利用する際には下記のようになります。

$this->load->driver('cache');
$this->cache->save('hoge', 'foo', 3600);
$foo = $this->cache->get('hoge');

システム全体でCacheドライバをロードしたかったので、autoload出来ないかソースを追ってみたのですが、できないようだったので、CI_Controllerを継承して独自のコントローラを作成し、下記のように__constructの中でロードすることにしました。

application/core/MY_Controller.php

class MY_Controller extends CI_Controller {
    function __construct() {
        parent::__construct();
        $this->load->driver('cache');
    }
}

このキャッシュの機構ですが、今仕事で使っている1.7.3にもbackport出来ないか調べています。出来るようであればパッチでも作成しようかなと思います。

今回、Cache周りのソースを読んでいてCI_Driver_Library、CI_Driverのソースが非常に面白く、特にCI_Driverの部分で特定のインスタンスのメソッド、フィールドをマジックメソッド経由でCI_Driverを継承したクラスから呼べるようにアタッチしている部分でした。自分でも正しく使える場面に遭遇すれば是非使ってみたい機構でした。

関連記事