動的Proxy
オブジェクト生成時のいろいろな指定はとりあえず無視しとく。
function p($s) { echo $s . "\n"; } class Object { function __get($name) { if (!isset($this->{$name})) { $this->{$name} = new $name(); } return $this->{$name}; } } class foo extends Object { //var $bar; 指定してしまうと__getが使えないのがネックかも function __construct() { p('foo::construct'); } function hoge($s) { p('foo::hoge'); return $this->bar->hoge($s.'foo'); } } class bar extends Object { //var $baz; function __construct() { p('bar::construct'); } function hoge($s) { p('bar::uni'); return $this->baz->hoge($s.'|bar'); } } class baz { function __construct() { p('baz::construct'); } function hoge($s) { p('baz::uni'); return $s.'|baz'; } }
メリット
- シンプル
- 余計なオブジェクト(プロキシクラス含む)を生成しない
デメリット
- 親クラスを継承する必要がある
- プロパティに指定を書けない
function p($s) { echo "$s\n"; } class Container { static function create($class) { $result = new $class(); foreach ($result as $p => $v) { $result->{$p} = new Proxy($p); } return $result; } } class foo { var $bar;//Proxy function __construct() { p('foo::construct'); } function hoge($s) { p('foo::hoge'); return $this->bar->hoge($s.'|foo'); } } class bar { var $baz; function __construct() { p('bar::construct'); } function hoge($s) { p('bar::hoge'); return $this->baz->hoge($s.'|bar'); } } class baz { function __construct() { p('baz::construct'); } function hoge($s) { p('baz::hoge'); return $s.'|baz'; } } class Proxy { private $ref; private $instance; function __construct($class) { $this->ref = new ReflectionClass($class); } function __get($name) { if (!isset($this->instance)) { $this->__instantiate(); } return $this->instance->{$name}; } function __set($name, $value) { if (!isset($this->instance)) { $this->__instantiate(); } $this->instance->{$name} = $value; } function __call($name, $args) { if (!$this->ref->hasMethod($name)) { // error echo "error\n"; } if (!isset($this->instance)) { $this->__instantiate(); } return $this->ref->getMethod($name)->invokeArgs($this->instance, $args); } function __instantiate() { $this->instance = Container::create($this->ref->getName()); } } $foo = Container::create('foo'); p ($foo->hoge('ccc') );