php 如何调用作为类变量的闭包?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7067536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:56:54  来源:igfitidea点击:

How to call a closure that is a class variable?

phplambdaclosuresanonymous-function

提问by rsk82

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()

So what is the correct syntax for reaching class variables ?

那么达到类变量的正确语法是什么?

回答by Arnaud Le Blanc

In PHP, methods and properties are in a separate namespace (you can have a method and a property with the same name), and whether you are accessing a property or a method depends of the syntax you are using to do so.

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

$expr->something()is a method call, so PHP will search somethingin the class' list of methods.

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

$expr->somethingis a property fetch, so PHP will search somethingin the class' list of properties.

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

$myInstance->lambda();is parsed as a method call, so PHP searches for a method named lambdain your class, but there is no such method (hence the Call to undefined methoderror).

$myInstance->lambda();被解析为方法调用,因此 PHP 搜索lambda在您的类中命名的方法,但没有这样的方法(因此调用未定义的方法错误)。

So you have to use the fetch propertysyntax to fetch the lambda, and then call it.

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

  • Since PHP 7.0, you can do this with ($obj->lambda)():

    ($obj->lambda)();
    

    The parentheses make sure that PHP parses ($obj->lambda)as fetch the property named lambda. Then, ()calls the result of fetching the property.

  • or you can do this with ->lambda->__invoke():

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

    __invokeis one of PHP's magic methods. When an object implements this method, it becomes invokable: it can be called using the $var()syntax. Anonymous functions are instances of Closure, which implements __invoke.

  • Or assign it to a local variable:

    $lambda = $myInstance->lambda;
    $lambda();
    
  • Or call it using call_user_func:

    call_user_func($myInstance->lambda);
    

    call_user_funccan call any callable, including anonymous functions.

  • Alternatively, if this is a common pattern in your code, you can setup a __callmethod to forward calls to your 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);
        }
    }
    

    Now this works:

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

    Since PHP 5.4 you can even do that in a 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();
    
  • 从 PHP 7.0 开始,您可以使用以下命令执行此操作($obj->lambda)()

    ($obj->lambda)();
    

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

  • 或者你可以这样做->lambda->__invoke()

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

    __invokePHP 的神奇方法之一。当一个对象实现这个方法时,它变得可调用:它可以使用$var()语法调用。匿名函数是 的实例Closure,它实现__invoke.

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

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

    call_user_func($myInstance->lambda);
    

    call_user_func可以调用 any 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();
    

回答by akDeveloper

You can also call your lambda function without change something in your class, using ReflectionFunction.

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

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

or if you have to pass arguments then

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

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