What is a Lambda Function
A lambda function (also known as anonymous function) is a function that has:
- No Name
- Can be assigned to a variable
- Can be passed as argument to other functions or methods of a class
In the past, this was possible with create_function like:
$multiply = create_function('$a, $b','return $a * $b;'); echo $multiply(5, 5); // 25
But it was a nuisance if you needed to write longer anonymous functions using create_function because it was difficult to write function body that way inside quotes and then escaping quotes and stuff.
PHP 5.3 introduced true support of lambda/anonymous functions similar to how you see in Javascript, so you could write above code like:
$multiply = function ($a, $b) < return $a * $b; >; echo $multiply(5, 5); // 25
As can be seen, above anonymous function has no name and has been assigned to variable $multiply . You can also pass it other functions:
function countEmails($number) < echo 'you have ' . $number . ' emails!'; >$multiply = function ($a, $b) < return $a * $b; >; echo countEmails($multiply(2, 5)); // you have 10 emails!
You could have also written above like this if you wanted:
function countEmails($multiply, $a, $b) < echo 'you have ' . $multiply($a, $b) . ' emails!'; >$multiply = function ($a, $b) < return $a * $b; >; echo countEmails($multiply, 2, 5); // you have 10 emails!
function countEmails($multiply, $a, $b) < echo 'you have ' . $multiply($a, $b) . ' emails!'; >echo countEmails(function ($a, $b) < return $a * $b; >, 2, 5); // you have 10 emails!
You can also assign it to array:
$array['multiply'] = function ($a, $b) < return $a * $b; >; echo $array['multiply'](2, 10); // 20
$obj = new StdClass(); $obj->multiply = function ($a, $b) < return $a * $b; >;
But caveat here is that instead of calling it like echo $obj->multiply(2, 10) , you would instead need to do:
$multiply = $obj->multiply; echo $multiply(2, 10); // 20
Now let’s create little program which says Hello, World using anonymous function:
$message = 'Hello, World!'; $sayHello = function () < echo $message; >; $sayHello();
Notice: Undefined variable: message
It means anonymous function does not have access to $message inside it. This is exactly when we need a closure to have access to that $message variable.
What is a Closure
A closure is a lambda/anonymous function that is aware of its surrounding context through the use of use keyword. It can access a variable outside of the scope where it is defined. Consider last $sayHello anonymous function and we convert it into closure through the use of use keyword and gain access to the $message variable:
$message = 'Hello, World!'; $sayHello = function () use ($message) < echo $message; >; $sayHello(); // Hello, World!
Thanks to closure ( use keyword), we are now able to access $message variable!
If you need to change the value of passed outside variable, you need to use reference of course:
$message = 'Hello, World!'; $sayHello = function () use (&$message) < echo $message; $message = 'Hello World Again!'; >; $sayHello(); // Hello, World! $sayHello(); // Hello World Again!
You can also pass regular arguments to closure:
$message = 'World!'; $sayHello = function ($arg) use ($message) < echo $arg . ' ' . $message; >; $sayHello('Hello'); // Hello, World!
You can also create a recursive function using closure easily, here is example of how you can create a factorial function:
$factorial = function( $n ) use ( &$factorial ) < if( $n == 1 ) return 1; return $factorial( $n - 1 ) * $n; >; echo $factorial( 5 );
Notice that $factorial is passed by reference using & otherwise it won’t work.
The difference between an anonymous function and closure is that closure has ability to access a variable outside of its scope by using the use keyword. So that is the subtle difference between an anonymous function and a closure. In fact, both are of them are instances of Closure class internally:
// anonymous function $multiply = function ($a, $b) < return $a * $b; >; $message = 'Hello, World'; // closure $sayHello = function () use ($message) < echo $message; >; var_dump ($multiply instanceof Closure); // true var_dump ($sayHello instanceof Closure); // true
Type Hinting
We know that you can already type hint few things:
But you can also type hint Closure as shown below:
function multiply($number, Closure $closure) < return $closure($number); >$closure = function($x)< return $x * 2; >; echo multiply(10, $closure);
Here we have made multiply function to require type of Closure as second parameter.
Use Cases
Anonymous functions and closures can be used in variety of situations.
As Callbacks
You can use them in your custom functions as callback or some of the PHP’s built-in functions such as array_map() , array_reduce() , array_filter() , array_walk() , etc. Let’s take example of array_walk() . If you look at it’s definition, here is how it looks:
bool array_walk ( array &$array , callable $callback [, mixed $userdata = NULL ] )
Notice the second parameter callable $callback . It means it expects something to be callable function. Anytime you see such parameter in some function definition, it means you can apply anonymous functions to it. Here is example:
$myArray = array(1, 2, 3, 4, 5); // multiply each array value with 2 array_walk($myArray, function(&$value, $index)< $value *= 2; >); print_r($myArray); Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
You might have seen closures being used in routing in framework like Laravel, Slim, Silex, etc:
$app = new \Slim\Slim($options); $app->get('/', function () use ($app) < $app->render('home', array('content' => 'Hello, World. ')); >);
Here $app is imported from outside scope into the scope of closure so that it can be used to render the view $app->render(. )
Accessing Private Members of a Class
We can use bind() or bindTo methods of Closure class to access private data of some class, for example:
class MyClass < private $variable = 'I am private variable!'; >$closure = function() < return $this->variable; >; $result = Closure::bind($closure, new MyClass(), 'MyClass'); echo $result(); // I am private variable!
There you see, we were able to get value of private variable $variable .
Similarly, it is also possible to add new behaviour to a class without actuallly modifying it direclty. Pretty cool hun ?
Lazy-loading a Class
Another ^cool^ thing you can do with closure is to lazy-load a class. For example:
class MyClass < public function __construct() < echo 'I am initialized!'; >> $getMyClass = function() < $myClass = new MyClass(); return $myClass; >;
If you run above code, you might expect to see I am initialized! message because one might think we are creating an instance of MyClass . That’s not true though, because code inside $getMyClass anonymous function is not run until you actually call it:
And now you would see the message I am initialized! . So this is pretty neat trick to defer some piece of code and use it only when you need it.
Класс Closure
Класс, используемый для создания анонимных функций.
Анонимные функции выдают объекты этого типа. Класс получил методы, позволяющие контролировать анонимную функцию после её создания.
Кроме методов, описанных здесь, этот класс также имеет метод __invoke . Данный метод необходим только для совместимости с другими классами, в которых реализован магический вызов, так как этот метод не используется при вызове функции.
Обзор классов
public static bind ( Closure $closure , ? object $newThis , object | string | null $newScope = «static» ): ? Closure
User Contributed Notes 4 notes
This caused me some confusion a while back when I was still learning what closures were and how to use them, but what is referred to as a closure in PHP isn’t the same thing as what they call closures in other languages (E.G. JavaScript).
In JavaScript, a closure can be thought of as a scope, when you define a function, it silently inherits the scope it’s defined in, which is called its closure, and it retains that no matter where it’s used. It’s possible for multiple functions to share the same closure, and they can have access to multiple closures as long as they are within their accessible scope.
In PHP, a closure is a callable class, to which you’ve bound your parameters manually.
It’s a slight distinction but one I feel bears mentioning.
Small little trick. You can use a closures in itself via reference.
Example to delete a directory with all subdirectories and files:
The Closure Class
A closure is an anonymous function, but an anonymous function is not a closure.
An anonymous function declares without any named identifier to refer to it. A closure is an anonymous function that closes over the environment in which it was defined. This means a closure can use of variables from outside its scope (parent scope).
PHP closures and anonymous functions (including arrow functions) use the same syntax as a function, but if you inspect a PHP closure or an anonymous function (or an arrow function), you’ll find they are instances of the Closure class:
; echo get_class($anony); # Prints: Closure echo gettype($anony); # Prints: object //Arrow function $arrow = fn() => 'im an arrow func'; echo get_class($arrow); # Prints: Closure echo gettype($arrow); # Prints: object
Use keyword
Variables are not accessible inside functions unless they are declared as global :
; echo $anony('World'); # Warning: Undefined variable $hello . on line 5
In much the same way, variables from the child scope are not accessible from within the closure unless explicitly stated using the use keyword:
; echo $closure('World'); # Prints: Hello World
A closure in PHP is an anonymous (lambda) function that encapsulates its surrounding state at the time it is created. The encapsulated state exists inside the closure even when the closure lives after its original environment ceases to exist.
Example: Passing multiple parameters and use multiple outer scope variables in a closure:
Closure class
PHP introduced the Closure class in the 5.3 version. The closure class is used to represent anonymous functions. Anonymous functions, implemented in PHP 5.3, yield objects of this type. Since PHP 5.4, the Closure class got several methods that allow further control of the anonymous function after it has been created.
bindTo() method
The bind() and bindTo() methods basically duplicate the Closure with a specific bound object and class scope.
Closures have the ability to capture a context from outside of the function’s scope (using use keyword). In addition to variables, this context can also be an object’s scope. This creates a closure object that has access to the properties of the object.
- the object to which the closure is bound
- the class scope that it is associated with it
To access private and protected , the name of the class must be specified as the second argument:
$closure = function () < return $this->hi; >; $getHi = $closure->bindTo(new A , 'A'); echo $getHi(); // Hello
bind() method
The bind() method has three parameters:
- The anonymous functions to bind
- The object to which the given anonymous function should be bound
- The class scope that it is associated with
$closure = function () < return $this->hi; >; $getHi = Closure::bind($closure,new A, 'A'); echo $getHi(); // Hello
Call() method
PHP 7 introduced the call method on a Closure class. The call method does not duplicate the closure, it temporarily binds the closure to the object, and calls it with any given parameters. It then returns the return value of the closure:
$closure = function () < return $this->hi; >; $getHi = $closure->call(new A); echo $getHi; // Hello
Note: you can replace the anonymous function with the arrow function, following is the modified example:
$closure = fn() => $this->hi; $getHi = $closure->call(new A); echo $getHi; // Hello
PHP OOP Tutorials: