我正在创建一个响应魔术__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
,这对反射不友好。具有匿名功能的属性作为方法在 PHP 5.4 中正常工作。
以反射将采用的方式将方法添加到类的唯一另一种方法是使用高度实验性的“runkit”扩展。