Php closure as argument

What is a Lambda Function

A lambda function (also known as anonymous function) is a function that has:

  1. No Name
  2. Can be assigned to a variable
  3. 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!

Читайте также:  Creating links in html using buttons

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 .

Читайте также:  Php pdo mysql install ubuntu

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.

Читайте также:  Что делает replace python

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:

Источник

Оцените статью