マジック__call()
メソッドに応答する動的クラスを作成しています。問題は、既存のフレームワーク (Kohana) の上にこれを構築しているため、 を使用してクラスのメソッドが存在するかどうかを確認し、その存在を確認するための魔法のメソッドReflectionClass::hasMethod
をトリガーしていないようです。__call()
この場合、どうすればよいですか?メソッドを動的に追加すると(のように$this->{$name} = function(){}
)、まだ「見る」ことができないようです
2 に答える
詳細がないと、これで十分かどうかはわかりませんが、中間機能を実行するプロキシ クラスを作成できます。
class MyProxy {
protected $_object = null;
protected $_methods = array();
public function __construct($object) {
if (!is_object($object)) {
throw new InvalidArgumentException('$object must be an object');
}
$this->_object = $object;
}
public function __call($name, $arguments) {
return $this->callMethod($name, $arguments);
}
public function setMethod($name, Closure $method) {
$this->_methods[(string) $key] = $method;
}
public function callMethod($name, array $arguments) {
if (isset($this->_methods[$name])) {
return call_user_func_array($this->_methods[$name], $arguments);
}
return call_user_func_array(array($this->_object, $name), $arguments);
}
}
を呼び出すことにより$proxy->setMethod('foo', function () { });
、メソッドをオブジェクトに動的に「アタッチ」できます。を呼び出すと$proxy->foo()
、最初に動的にアタッチされたメソッドに対して検索が行われます。見つかった場合は、それを呼び出します。それ以外の場合は、内部オブジェクトに委譲するだけです。
さて、このアプローチの問題点は、アタッチされたメソッドがプロキシにバインドされていないことです。つまり、$this
アタッチされたメソッドのスコープには存在しません。
ただし、これは PHP 5.4 以降の機能で修正できます。
public function setMethod($name, Closure $method) {
$this->_methods[(string) $name] = Closure::bind($method, $this);
}
渡されたクロージャをプロキシに再バインドするように改良setMethod
しました。これで、アタッチされたメソッドのスコープ内で、プロキシ オブジェクトがポイントされます。$this
囲まれたオブジェクトに再バインドすることもできましたが、アタッチされたメソッドはプロキシ (または他のアタッチされたメソッド) と通信できませんでした。完全を期すために、プロパティアクセス/変更呼び出しを内部オブジェクトに転送する(またはプロキシでそれらを処理するなど)ために、追加__get
して魔法をかけたいと思うでしょう。__set
その上、内部オブジェクトはプロキシについての手がかりがないため、(クラス定義からの) メソッドはとにかくこの動的な魔法について知りません。
メソッドを動的に追加した場合のようです(
$this->{$name} = function(){})
まだ「見る」ことができないように)
そうです、メソッドではなく新しいプロパティを作成しているためです。これを書いている時点では、PHP は を介さずにプロパティで無名関数を呼び出すことをサポートしていませんでした__call
。これは Reflection に適していません。メソッドとしての匿名関数を持つプロパティは、PHP 5.4 で適切に機能します。
Reflection が認識できる方法でクラスにメソッドを追加する他の唯一の方法は、非常に実験的な「runkit」拡張機能を使用することです。