【问题标题】:How to call a closure that is a class variable?如何调用作为类变量的闭包?
【发布时间】:2011-10-27 09:47:21
【问题描述】:
class MyClass {
  var $lambda;
  function __construct() {
    $this->lambda = function() {echo 'hello world';};
    // no errors here, so I assume that this is legal
  }
}

$myInstance = new MyClass();
$myInstance->lambda();
//Fatal error: Call to undefined method MyClass::lambda()

那么访问类变量的正确语法是什么?

【问题讨论】:

    标签: php lambda closures anonymous-function


    【解决方案1】:

    在 PHP 中,方法和属性位于单独的命名空间中(您可以拥有同名的方法和属性),您访问的是属性还是方法取决于您使用的语法。

    $expr->something() 是一个方法调用,所以 PHP 会在类的方法列表中搜索 something

    $expr->something 是一个属性获取,因此 PHP 将在类的属性列表中搜索 something

    $myInstance->lambda(); 被解析为方法调用,因此 PHP 在您的类中搜索名为 lambda 的方法,但没有这样的方法(因此出现 Call to undefined method 错误)。

    所以你必须使用 fetch property 语法来获取 lambda,然后调用它。

    • 从 PHP 7.0 开始,您可以使用 ($obj->lambda)()

      ($obj->lambda)();
      

      括号确保 PHP 将 ($obj->lambda) 解析为 获取名为 lambda 的属性。然后,() 调用获取属性的结果。

    • 或者您可以使用->lambda->__invoke()

      $myInstance = new MyClass();
      $myInstance->lambda->__invoke();
      

      __invokePHP's magic methods 之一。当一个对象实现了这个方法时,它就变成了可调用的:可以使用$var() 语法来调用它。匿名函数是Closure 的实例,它实现了__invoke

    • 或将其分配给局部变量:

      $lambda = $myInstance->lambda;
      $lambda();
      
    • 或者使用 call_user_func 调用它:

      call_user_func($myInstance->lambda);
      

      call_user_func 可以调用任何callable,包括匿名函数。

    • 或者,如果这是您代码中的常见模式,您可以设置 __call 方法来将调用转发到您的 lambda:

      class MyClass
      {
          private $lambda;
      
          public function __construct()
          {
              $this->lambda = function() {
                  echo "Hello world!\n";
              };
          }
      
          public function __call($name, $args)
          {
              return call_user_func_array($this->$name, $args);
          }
      }
      

      现在可以了:

      $myInstance = new MyClass();
      $myInstance->lambda();
      

      从 PHP 5.4 开始,您甚至可以在 trait 中做到这一点:

      trait LambdasAsMethods
      {
          public function __call($name, $args)
          {
              return call_user_func_array($this->$name, $args);
          }
      }
      
      class MyClass
      {
          use LambdasAsMethods;
      
          private $lambda;
      
          public function __construct()
          {
              $this->lambda = function() {
                  echo "Hello World!\n";
              };
          }
      }
      
      $myInstance = new MyClass();
      $myInstance->lambda();
      

    【讨论】:

    • 很好,虽然很高兴看到 __invoke/()call_user_func 的注释。
    • 你几乎可以对所有东西使用特征,它不是一个类,只是一组松散的方法和道具
    • 这不是站起来的:$myInstance->lambda();被解析为方法调用,因此 PHP 在您的类中搜索名为 lambda 的方法,但没有这样的方法(因此出现 Call to undefined method 错误)..。调用self::$my_closure() 也不起作用。虽然很明显我在调用一个属性。
    【解决方案2】:

    您还可以使用 ReflectionFunction 调用您的 lambda 函数,而无需更改类中的某些内容。

    $myInstance = new MyClass();
    $lambda = new ReflectionFunction($myInstance->lambda);
    $lambda->invoke();
    

    或者如果你必须传递参数,那么

    $args = array('arg'=>'value');
    $lambda->invokeArgs($args);
    

    【讨论】:

    • 这不是最短的,也不是最有效的方法。
    猜你喜欢
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-08
    • 1970-01-01
    相关资源
    最近更新 更多