2011-04-09 56 views
3

我正在创建一个响应魔术__call()方法的动态类。问题是,因为我在已经存在的框架(Kohana)的基础上构建了它,所以它检查类的方法是否存在使用ReflectionClass::hasMethod,并且它似乎没有触发__call()魔术方法来检查它是否存在。我能在这种情况下做什么?似乎如果你动态添加方法(如$this->{$name} = function(){})它仍然不能“看到”它PHP ReflectionClass hasMethod和__call()

回答

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); 
} 

我们已经细化到setMethodrebind the passed closure代理。现在,在附加方法的范围内,$this将指向代理对象。

我们可以将它反弹回所包含的对象,但随后附加的方法无法与代理(或其他附加方法)通信。为了完整起见,你要添加__get__set魔术,转发属性访问/突变调用内部对象(或代理处理它们,无论

此外,内部的对象有没有关于线索代理,所以它的方法(类定义中的)无论如何都不会知道任何这种动态魔术。

1

好像如果你动态地添加的方法(如$this->{$name} = function(){})它仍然无法“看到”它

权,因为你正在创建一个新的财产,而不是一个方法。在在写作时,PHP不支持在属性中调用匿名函数,而不通过__call,这不是反射友好的。在PHP 5.4中,使用匿名函数作为方法的功能可以正常工作

唯一的其他以Refl的方式将方法添加到类中的方法ection将会采用highly experimental "runkit" extension