【问题标题】:Storing a Closure Function in a Class Property in PHP在 PHP 中的类属性中存储闭包函数
【发布时间】:2012-08-25 03:41:29
【问题描述】:

好的,我确实有下面的代码

<?php
    class foo{
       public $bar = NULL;

       public function boo(){
          $this->bar();
       }
    }

    $mee = new foo();

    //save a closure function on the property
    $mee->bar = function(){
        echo 'hahaha';
    };

    //invoke the closure function by using a class method
    $mee->boo();
?>

你可以看到它在这里运行http://codepad.org/s1jhi7cv

现在我想要的是将闭包函数存储在类方法上。

当我在http://php.net/manual/en/functions.anonymous.php阅读有关它的文档时,可能会关闭

这可能吗?我是不是做错了什么?请纠正我

【问题讨论】:

  • 您不应该为此使用“codepad.org”,他们使用的是相当旧的 PHP 版本,还不支持闭包。

标签: php class function methods closures


【解决方案1】:

您在 codepad.org 上的示例代码不起作用,因为 codepad.org 使用 PHP 5.2.5,并且仅在 5.3 中添加了闭包支持。

但是,您的代码也无法在支持闭包的 PHP 版本中运行,尽管您会收到不同的错误:http://codepad.viper-7.com/Ob0bH5

这是目前 PHP 的一个限制。 $obj-&gt;member() 查找名为 member 的方法,并且不会查看属性以查看它们是否可调用。坦率地说,这很烦人。

我知道在没有call_user_func()/call_user_func_array() 的情况下完成这项工作的唯一方法是:

public function boo() {
   $func = $this->bar;
   $func();
}

【讨论】:

  • @Mahan 它在 codepad.org 上不起作用(请参阅上面的编辑),您至少需要 5.3。作品here
【解决方案2】:

您需要利用 PHP (__call) 的一些神奇功能来利用它。例如从Extendable 扩展:

class Extendable {
    static function import($context) {
        $self = new static();
        while (is_callable($context)) $context = $context($self);
        if (is_array($context) || is_object($context) || is_a($context, 'Traversable')) {
            foreach($context as $key => $value)
                $self->$key = &$value; # preserve keys if
        }
        return $self;
    }
    public function __call($name, $args) {
        if (isset($this->$name) && is_callable($this->$name)) {
            return call_user_func_array($this->$name, $args);
        }
        throw new BadFunctionCallException(sprintf('Undefined function %s.', $name));
    }
}

你可以完成这项工作。这不是很好。背景和示例在我的一篇博文中:

您也可以自然地实现自己的神奇功能。

【讨论】:

  • 很好,如果你想用这个功能扩展一些其他的基类,也可以很容易地变成一个特征。
  • 是的,没错。但是我不知道将特征用于魔术功能是否一开始就没有麻烦;)
  • +1。不过,我会抛出 BadMethodCallException
  • 是的,我在写评论后就是这么想的。尽管由于仍然可以覆盖特征方法,因此几乎没有消除危险,但这破坏了特征的整个目的。嗯。
  • @drrcknlsn:或者可能是UnexpectedValueException。这些异常名称在 PHP 中是一团糟:I)
【解决方案3】:

你将无法做到这一点。

以这段代码为例:

class T {
  function foo() {
    echo 'T::foo';
  }
}

$t = new T;
$t->foo = function() {
  echo 'Closure::foo';
};
$t->foo();

它在 PHP 5.4.6 和/或 PHP 5.3.16 上运行良好,但它会导致 T::foo 被打印出来。

发生这种情况是因为 PHP 中的方法不是可修改的类属性,例如在 javascript 中。

然而,

$foo = $t->foo;
$foo();

将按预期打印Closure::foo

【讨论】:

    【解决方案4】:

    使用call_user_func()函数:

    <?php
        class foo{
           public $bar = NULL;
    
           public function boo(){
              call_user_func($this->bar);
           }
        }
    
        $mee = new foo();
    
        //save a closure function on the property
        $mee->bar = function(){
            echo 'hahaha';
        };
    
        //invoke the closure function by using a class method
        $mee->boo();
    

    这将显示“啊哈”

    希望对你有帮助。

    【讨论】:

    • 其实会显示“哈哈哈”:D
    【解决方案5】:

    PHP 不是基于原型的语言,因此您无法重新定义函数

    【讨论】:

      【解决方案6】:

      使用__call 捕获所有未定义的方法,然后查找闭包并调用它。看看我在 SitePoint thread 上的帖子。

      【讨论】:

      • 你能给一个示例代码吗?抱歉,我没有使用 __call 的经验,谢谢
      • __call 的示例函数,您也可以在 my answer 中找到。
      • 外部链接失效。
      猜你喜欢
      • 1970-01-01
      • 2018-08-26
      • 2020-07-26
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      • 1970-01-01
      • 2015-04-29
      相关资源
      最近更新 更多