【问题标题】:How to bind $this to a closure that is passed as a method parameter in PHP 5.4?如何将 $this 绑定到在 PHP 5.4 中作为方法参数传递的闭包?
【发布时间】:2013-12-26 10:28:12
【问题描述】:

有没有办法将$this 绑定到作为参数传递的闭包? 我阅读并重新阅读了我可以在手册或互联网上找到的所有内容,但没有人提到这种行为,除了这篇博文: http://www.christophh.net/2011/10/26/closure-object-binding-in-php-54/ 其中提到了它,但没有说明如何做。

所以这里有一个例子。当调用get(function() {}) 方法时,我希望传递给它的回调函数绑定到对象,即绑定到$this,但不幸的是它不起作用。有什么办法可以吗?

class APP
{
    public $var = 25;

    public function __construct() {

    }
    public function get($callback) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Paran must be callable.');
        }
        // $callback->bindTo($this);
        $callback->bindTo($this, $this);
        $callback();
    }
}

$app = new APP();
$app->get(function() use ($app) {
    echo '<pre>';
    var_dump($app);
    echo '<br />';
    var_dump($this);
});

$app 有效。 $this 为 NULL。

【问题讨论】:

    标签: php php-5.4


    【解决方案1】:

    只需将其作为参数传递:

        public function get($callback) {
            if (!is_callable($callback)) {
                throw new InvalidArgumentException('Paran must be callable.');
            }
            // $callback->bindTo($this);
            return $callback($this);
        }
    
    ...
    
    $app = new APP();
    $app->get(function($that) use ($app) {
        echo '<pre>';
        var_dump($app);
        echo '<br />';
        var_dump($that);
    });
    

    或者,如果您确实需要绑定它,则必须使用返回函数的函数,如下所示:

        public function getCallback($callback) {
            return function($app){
                return $callback($this, $app);
            }
        }
    
    ...
    
    $app = new APP();
    $f = $app->get(function($that, $app) {
        echo '<pre>';
        var_dump($app);
        echo '<br />';
        var_dump($that);
    });
    $f($app);
    

    【讨论】:

    • 谢谢Benubird(喜欢你的名字:)),我已经知道解决方法(正如我所说,我几乎阅读了我能找到的关于这个主题的所有内容),但它看起来真的很难看,我虽然如果一种语言实现了闭包,这应该是可以更直接地实现的。
    【解决方案2】:

    我实际上不明白为什么在这种情况下使用 bindTo 方法不起作用,但我可以使用 Closure::bind 让它工作

    public function get($callback) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Param must be callable.');
        }
    
        $bound = Closure::bind($callback, $this);
        $bound();
    }
    

    编辑

    显然bindTo 方法具有相同的行为,因此您应该将其返回值重新分配给$callback。例如:

    public function get($callback) {
        if (!is_callable($callback)) {
            throw new InvalidArgumentException('Param must be callable.');
        }
    
        $callback = $callback->bindTo($this);
        $callback();
    }
    

    【讨论】:

    • 该死!非常感谢吉尔赫姆!我尝试了 Closure::bind,但我不知道这是我应该调用的返回值。
    • 在一行中$callback-&gt;bindTo($this)-&gt;__invoke(); :)
    • 你确定is_callable检查就够了吗?如果我将 [$someObject, 'existedMethod'] 传递给您的函数,它将通过可调用检查(因为它是有效的可调用变量)并在绑定行失败。
    • @kirugan 我回答了很久。我真的没有考虑到这一点,因为询问的人打算使用匿名函数作为回调。如果您为此用例解决了问题,请随时对其进行编辑并添加更多详细信息。 :)
    【解决方案3】:

    这样做:

    class APP
    {
      public $var = 25;
    
      public function __construct() {}
    
      public function get($callback) {
        if (!is_callable($callback)) {
          throw new InvalidArgumentException('Param must be callable.');
        }
        // $callback->bindTo($this);
        // you must save result in another var and call it
        $callback1 = $callback->bindTo($this, $this);
        $callback1();
      }
    }
    
    $app = new APP();
    $app->get(function() use ($app) {
      echo '<pre>';
      var_dump($app);
      echo '<br />';
      var_dump($this);
    });
    

    【讨论】:

    • 这也有效!所以绑定的是返回的闭包,而不是原来的闭包。
    【解决方案4】:

    一个小修正:不要使用is_callable来检查Closure是否被参数传递。

    因为is_callable 也接受带有函数名称的字符串。

    public function get(\Closure $callback) {
    
        $bound = \Closure::bind($callback, $this);
        $bound();
    }
    

    有了is_callable,我们就有了这种可能性:

    $app = new App;
    
    
    $app->get('my_function');
    

    如果函数存在,则抛出此错误:

    Closure::bind() 期望参数 1 是 Closure,给定字符串

    因为“My_function”在is_callable 的测试中通过,但Closure::bind 期望Closure 的实例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 2017-12-11
      • 2012-07-24
      • 2012-11-12
      • 2013-09-13
      • 1970-01-01
      相关资源
      最近更新 更多