匿名函数/闭包和使用self::或static::

10

我正在使用匿名函数,我在对象外创建一个匿名函数,然后稍后将其添加到对象中,在其中使用__callStatic魔术函数。被添加的闭包包含来自父类的方法。我想知道是否能够从闭包中调用这些方法?

目前我得到了这个错误:

EmptyObject::addMethod('open', function(){
    if (static::_hasAdapter(get_class(), __FUNCTION__))
            return self::_callAdapter(get_class(), __FUNCTION__, $details);

    echo '<p>You have mail!</p>';
});

抛出此错误:

致命错误:在没有类范围活动时无法访问 static::

以及

//Add the functions
EmptyObject::addMethod('open', function(){
    if (EmptyObject::_hasAdapter('EmptyObject', __FUNCTION__))
            return EmptyObject::_callAdapter('EmptyObject', __FUNCTION__, $details);

    echo '<p>You have mail!</p>';
});

因为该方法是受保护的,所以会引发此错误。

Fatal error: Uncaught exception 'BadMethodCallException' with message 'Method '_hasAdapter' was not found in class EmptyObject'


旧的 PHP.. 在 5.5.9 版本中,我可以在匿名函数中看到 'static::'。 - Dariux
3个回答

15

您可以使用 Closure::bind()(PHP >= 5.4.0)来实现此目的。

abstract class EmptyObject
{
   protected static $methods = array();

   final public static function __callStatic($name, $arguments)
   {
      return call_user_func(self::$methods[$name], $arguments);
   }

   final public static function addMethod($name, $fn)
   {
      self::$methods[$name] = Closure::bind($fn, NULL, __CLASS__);
   }

   final protected static function protectedMethod()
   {
      echo __METHOD__ . " was called" . PHP_EOL;
   }
}
现在,传递给EmptyObject :: addMethod()的任何匿名函数将在EmptyObject类的作用域中运行。
EmptyObject::addMethod("test", function()
{
   self::protectedMethod();
});


// will output:
// EmptyObject::protectedMethod was called

EmptyObject::test();

1
在使用后期静态绑定时,应省略__CLASS__参数(或将其设置为“static”,例如默认值)。 - Boris Belenski

14

只需存储类名,并通过use将其传递给闭包。您可以以这种方式调用任何公共静态方法或获取公共静态属性或常量。如果将闭包传递到不同的上下文中,只要在创建闭包时正确传递了$class的值,它仍将起作用。适用于php 5.3:

class test {
    public static function callMe() { echo 'call me '; }

    public static function runTest() {
        $class = __CLASS__;
        $call = function() use ($class) {
            $class::callMe();   
        };
        $call();
    }
}
test::runTest();

3
闭包之所以被称为闭包,是因为它们“封闭”了它们所定义的作用域。它们不仅仅是可以从粘贴位置中捕获作用域的代码块。请点击此处了解更多信息。

有道理,但是如果不将该方法公开,你如何完成上述操作呢?在JavaScript中,您只需将函数保存到本地变量中,并在闭包内调用它。在PHP中,您该如何做呢? - Daniel Beardsley
JavaScript和PHP中作用域的工作方式非常不同。从PHP中外部作用域在函数内不可见开始,到JavaScript中您可以更改执行函数的范围结束。换句话说:PHP不适合这样的元编程。也许您可以使用Reflection扩展做些什么,但我对此不确定。另一种方法可能是使用eval,但那有它自己的缺点。 - Mchl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接