Как вызвать замыкание, являющееся переменной класса? - PullRequest
73 голосов
/ 15 августа 2011
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()

Так, каков правильный синтаксис для достижения переменных класса?

Ответы [ 2 ]

184 голосов
/ 15 августа 2011

В PHP методы и свойства находятся в отдельном пространстве имен (у вас может быть метод и свойство с одинаковым именем), и от того, какой синтаксис вы используете для этого, зависит доступ к свойству или методу.

$expr->something() - это вызов метода, поэтому PHP будет искать something в списке методов класса.

$expr->something - это выборка свойств, поэтому PHP будет искать something в списке свойств класса.

$myInstance->lambda(); анализируется как вызов метода, поэтому PHP ищет метод с именем lambda в вашем классе, но такого метода нет (следовательно, вызов неопределенного метода ошибка).

Таким образом, вы должны использовать синтаксис fetch *1018* fetch для извлечения лямбды, а затем вызывать ее.

  • Начиная с PHP 7.0, вы можете сделать это с помощью ($obj->lambda)():

    ($obj->lambda)();
    

    Скобки гарантируют, что PHP анализирует ($obj->lambda) как и извлекает свойство с именем lambda . Затем () вызывает результат извлечения свойства.

  • или вы можете сделать это с помощью ->lambda->__invoke():

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

    __invoke - это один из магических методов PHP . Когда объект реализует этот метод, он становится активным: его можно вызывать с использованием синтаксиса $var(). Анонимные функции - это экземпляры Closure, которые реализуют __invoke.

  • Или назначьте его локальной переменной:

    $lambda = $myInstance->lambda;
    $lambda();
    
  • Или позвоните по телефону call_user_func:

    call_user_func($myInstance->lambda);
    

    call_user_func может вызывать любой callable, включая анонимные функции.

  • В качестве альтернативы, если это обычный шаблон в вашем коде, вы можете настроить __call метод для переадресации вызовов на вашу лямбду:

    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 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();
    
2 голосов
/ 29 июня 2013

Вы также можете вызвать свою лямбда-функцию без каких-либо изменений в вашем классе, используя ReflectionFunction.

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

или если вам нужно передать аргументы, тогда

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