Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a closure that is a class variable?

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 ?

like image 340
rsk82 Avatar asked Aug 15 '11 16:08

rsk82


People also ask

What is class closure?

The Closure class ¶Class used to represent anonymous functions. Anonymous functions yield objects of this type. This class has methods that allow further control of the anonymous function after it has been created. Besides the methods listed here, this class also has an __invoke method.

What is closure variable?

A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

What is closure call?

Closure::call() method is added as a shorthand way to temporarily bind an object scope to a closure and invoke it. It is much faster in performance as compared to bindTo of PHP 5.6.

How would you use a closure to create a private counter?

3How would you use a closure to create a private counter? You can create a function within an outer function (a closure) that allows you to update a private variable but the variable wouldn't be accessible from outside the function without the use of a helper function.


1 Answers

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.

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

$expr->something is a property fetch, so PHP will search something in the class' list of properties.

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

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

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

    __invoke is 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_func can call any callable, including anonymous functions.

  • Alternatively, if this is a common pattern in your code, you can setup a __call method 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(); 
like image 174
Arnaud Le Blanc Avatar answered Sep 16 '22 20:09

Arnaud Le Blanc