これを知らなく、必死でmemcacheコマンドのgetを叩いて、あれ!?って
なってました。
FuelPHPでMemcachedを使うには?
configのcache.phpで
return array(
'driver' => 'memcached',
'expiration' => 86400,
'memcached' => array(
'cache_id' => 'fuel', others stored on the same server(s)
'servers' => array(
'default' => array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
),
),
);
こんな感じで設定してあげれば、FuelPHPでラッパークラスを通して、Memcachedが使えるわけです。
Cache::set('test', 'hoge');
Cache::get('test');
中身を確認しようとして、直接コマンドを叩いても・・・・
sshでサーバにログインして
[nameko@centos]telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get test
END
testをキーに値を取り出そうとしても、なにもありません!!
FuelPHPでのキャッシュクラスを整理
memcachedをラップしているクラスを整理すると
- Fuel\Core\Cache
- Fuel\Core\Cache_Storage_Memcached (継承元はCache_Storage_Driver)
Fuel\Core\Cacheクラス
こいつがユーザにキャッシュ操作を提供する表向きのクラスです。
forge,set,getの実装見てみるとわかりますが
/* 行の節約でコメントは削除 */
public static function forge($identifier, $config = array())
{
$defaults = \Config::get('cache', array());
if ( ! empty($config) and ! is_array($config) and ! is_null($config))
{
$config = array('driver' => $config);
}
$config = array_merge($defaults, (array) $config);
if (empty($config['driver']))
{
throw new \FuelException('No cache driver given or no default cache driver set.');
}
$class = '\\Cache_Storage_'.ucfirst($config['driver']);
$identifier = call_user_func($class.'::stringify_identifier', $identifier);
return new $class($identifier, $config);
}
public static function set($identifier, $contents = null, $expiration = false, $dependencies = array())
{
$contents = \Fuel::value($contents);
$cache = static::forge($identifier);
return $cache->set($contents, $expiration, $dependencies);
}
public static function get($identifier, $use_expiration = true)
{
$cache = static::forge($identifier);
return $cache->get($use_expiration);
}
get,setするごとにforgeしてる!!
$class = '\\Cache_Storage_'.ucfirst($config['driver']);
$identifier = call_user_func($class.'::stringify_identifier', $identifier);
return new $class($identifier, $config);
ここでCache_Storage_Memcachedクラスをインスタンス化してますね。
set,getへの操作はそれぞれ1:1でMemcachedのストレージインスタンスに対応してるわけです。
Fuel\Core\Cache_Storage_Memcachedクラス
継承元はCache_Storage_Driveです。
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
~~~~~省略
static::$memcached = new \Memcached();
static::$memcached->addServers($this->config['servers']);
}
こいつをインスタンス化すると、Memcachedクラスをインスタンス化して、configの情報を元に、addServersしてるわけです。
Cache_Storage_Driveは、実装ストレージに依存されない、処理や値の管理をしていますね。
ちなみに、Cache::get,setは、
Cache_Storage_Driveのget,setになります
Cache_Storage_Driveのget,setで、
子クラスのCache_Storage_Memcachedの_get,_setメソッドが呼ばれます。
ややこしいですね。
ここらへんは、提供するメソッドと実際処理するメソッドの分離をするための設計でしょうか。
Fuel自体、委譲をたくさん使い、差し替え可能や、分離させるための設計があちこちで見られます。
それでは、Cache_Storage_Memcachedのset,getを見てみます。
/* 行の節約でコメントは削除 */
protected function _set()
{
$key = $this->_get_key();
$payload = $this->prep_contents();
$expiration = !is_null($this->expiration) ? $this->expiration - time() : 0;
$expiration = $expiration <= 2592000 ? (int) $expiration : (int) $this->expiration;
if (static::$memcached->set($key, $payload, $expiration) === false)
{
throw new \FuelException('Memcached returned error code "'.static::$memcached->getResultCode().'" on write. Check your configuration.');
}
$this->_update_index($key);
return true;
}
protected function _get()
{
$key = $this->_get_key();
$payload = static::$memcached->get($key);
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
static::を使ってやがる・・・・
いかした設計にはもちろん遅延静的束縛 (Late Static Bindings) も使うぜ!!
$key = $this->_get_key();
こいつの探ると・・・
protected function _get_key($remove = false)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier][0] : false;
if ($remove === true)
{
if ( $key !== false )
{
unset($index[$identifier]);
static::$memcached->set($this->config['cache_id'].$sections, $index);
}
}
else
{
// create a new key if needed
$key === false and $key = $this->_new_key();
}
return $key;
}
protected function _new_key()
{
$key = '';
while (strlen($key) < 32)
{
$key .= mt_rand(0, mt_getrandmax());
}
return md5($this->config['cache_id'].'_'.uniqid($key, TRUE));
}
_new_key()メソッドが、ハッシュキーを生成してる部分です!
cache_idはconfigで指定した任意の文字列で、uniqidしてるkeyはrandomで出した値ですね。
ユーザが指定したキーとは全く関係ない、ユニークな値が生成され、
これがMemcachedのキーになるわけです。
効率よくMemcachedに入っている値を取り出すには
Memcachedへの操作をラップしているCacheクラスを使えば、
内部の実装を意識せず、値の取り出し、設定ができます。
でもサーバにログインして、直接を値を確認したいときもあるじゃないですか。
どうやってユニークなハッシュキーを探せばいいかというと、
上記で登場したcache_idの値でgetしてみてください。
cache_idをfuelにしていた場合
[nameko@centos]telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get fuel
test ffe1d667f601bfd95ca91b79c35dda63
END
なんと、元のキーとハッシュキーの対応を、cache_idをキーにした
Memcachedの値で保持してるのです!!
この対応表をFuelのキャッシュクラスが管理して、取得、設定の面倒を見てくれてるのですね。
なので直接Memcachedの値を確認したいときは、この対応を確認して
取り出したい値のハッシュキーをチェックしましょう。
[nameko@centos]telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get ffe1d667f601bfd95ca91b79c35dda63
hoge
END
画面で確認したい
面倒なので、画面でMemcachedにセットしてる一覧を見たい!!
という場合は、
class Logic_Memview extends \Cache_Storage_Memcached
{
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
}
public function get_all()
{
$indexs = $this->_get_index();
$cache_index_list = $indexs[2];
$cache_list = array();
if ($cache_index_list)
{
foreach ($cache_index_list as $cache_key => $index_values)
{
$instance = new self($cache_key, $this->config);
try
{
$cache_data = $instance->get();
} catch (\Exception $e)
{
$cache_data = '';
}
$cache_list[$cache_key] = array('data' => $cache_data, 'hash_key' => $index_values[0]);
}
}
return $cache_list;
}
}
\Cache_Storage_Memcachedを継承し、get_allメソッドを実装してます。
コントローラでこいつをインスタンス化して、get_allメソッドを呼び出せば、
(cache_optionはcacheのconfig値をいれてください)
$logic = new Logic_Memview('test', $cache_option);
$cache_data_list = $logic->get_all();
キー、ハッシュキー、値の配列が取得できます
あとはこれをviewで表示すれば、見やすい一覧ができると思います。