ClassRegistry徹底解剖
ClassRegistryについてごく詳細までまとめられている日本語の記事が見当たらないので、纏めてみようと思います。
ClassRegistryとは
シングルトンパターンのクラスのオブジェクトをkeyを元に包括的に管理をします。
生成・初期化・生成済みオブジェクトの参照を保存/提供します。
モデルとその他
ClassRegistryはモデルオブジェクトとその他のオブジェクトを区別します。
あまり意識せずとも使えるようにはなっています。
API解説
Object &ClassRegistry::init(mixed $class, string $type = null)
クラスのインスタンスを生成・初期化し、その参照を保存します。単一のクラスが指定されたときそのインスタンスの参照を、複数の場合は全てが成功したかどうか(boolean)を返します。
モデルオブジェクトの場合、エイリアスマッピングが自動的に行われます。
$classにはオブジェクトのclass名称またはその配列を指定します。
$typeにはオブジェクトのタイプを指定します。何も指定しないと'Model'になります。
なお、$typeはそのままApp::import($type, /* ... */);に渡されます。
$classは配列指定が可能で、以下の様式を取れます。
// 複数のオブジェクトを指定(成功結果はtrueを返す) array( 'Object1', 'Object2', 'Object3', )
// 初期化設定を指定(返り値はオブジェクトの参照) array( 'class' => 'Object', 'someParameter1' => 'hoge', 'someParameter2' => 'piyo', )
// 複数のオブジェクトに初期化設定を指定 array( array( 'class' => 'Object1', 'someParameterA' => 'hoge', 'someParameterB' => 'piyo', ), array( 'class' => 'Object2', 'someParameterC' => 'huga', 'someParameterD' => 'moge', ), )
オブジェクトの初期化を行い、それがモデル以外のオブジェクトであれば、参照を保存します。
初期化の際、以下のように第一引数にパラメータの配列が渡ります。
${$class} =& new $class($settings); // ソースから引用
この$settingsのデフォルトは、ClassRegistry::config()で指定されたものになります。
※重要
指定されたオブジェクトを読み込めない(ファイルパス、クラス定義が見つからない)場合、モデルはAppModelのインスタンスとして読み込まれます。
バリデーションを設定しているのに全通しになってしまうなどの場合は、これを疑ったほうがいいかもしれません。
bool ClassRegistry::addObject(string $key, object &$object)
$keyに対してオブジェクトの参照を格納します。
これはClassRegistry::init()を経由せず、自らオブジェクトを初期化した上で登録するのに適しています。
bool ClassRegistry::removeObject(string $key)
$keyに合致するオブジェクトが読み込まれてる場合、そのオブジェクトへの参照を破棄します。
bool ClassRegistry::isKeySet(string $key)
$keyに合致するオブジェクトが読み込まれているかをtrue/falseで返します。
array ClassRegistry::keys()
既に読み込まれているオブジェクトのキー一覧を配列で返します。
Object &ClassRegistry::getObject(string $key)
$keyに合致するオブジェクトが既に読み込まれていれば、それの参照を返します。
bool ClassRegistry::config(string $type, array $param = array())
$typeで指定されるタイプのオブジェクトを初期化をする際のデフォルトの設定をします。
第一引数に配列を指定、第二引数を指定しないと、タイプが'Model'となり、第一引数がパラメータとして扱われます。
第一引数に文字列を指定、第二引数を指定しないと、$typeに対応する設定を返します。
$paramにnullを指定すると$typeの設定を破棄します。
bool ClassRegistry::map(string $key, string $name)
$keyに対応する$nameを指定すると、エイリアス指定が可能になります。
Example:
<?php $object = new HogeObject; ClassRegistry::addObject('HogeObject', $object); ClassRegistry::map('Hoge', 'HogeObject'); $hoge =& ClassRegistry::getObject('Hoge'); // success
サンプルコード
初期化設定を利用して、動的にモデルの$useDbConfigを変更する
<?php // bootstrap.php など App::import('Core', 'ClassRegistry'); if(/* テストサーバーのみが満たす要件 */){ ClassRegistry::config(array('ds' => 'test')); } ?>
任意のオブジェクトを引数無しで初期化する(init()代替)関数
<?php function &loadObject($name, $type = 'Core'){ $false = false; list($plugin,$class) = pluginSplit($name); $pluginPath = ($plugin)? $plugin . '.' : null; if(class_exists($class)){ if(ClassRegistry::isKeySet($class)){ $object =& ClassRegistry::getObject($class); return $object; } }else{ App::import($type, $pluginPath . $class); } if(!class_exists($class)){ return $false; } $object =& new $class(); if($object === null){ return $false; } ClassRegistry::addObject($class, $object); return $object; } ?>
最後に
使い方を強制するわけではありませんが、ClassRegistryを乱暴に使うと、MVCが破壊されることがあります。が、それは望まれないことです。
勢い余ってビューでモデルを呼んだりしないようにしましょう :D