Exploring Lambda Functions and Closures in PHP
Tags: php
Published: 2020-01-28 09:43:47

---
title: Exploring Lambda Functions and Closures in PHP
published: true
tags: php
canonical_url: https://codeinphp.github.io/post/exploring-lambda-functions-and-closures-in-php/
---

# 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`](http://php.net/manual/en/function.create-function.php) 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!
```

And even like this:

```
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
```

And even an object:

```
$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();
```

Oops, it results in error:

`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:

- Object
- Array
- Interface
- callable

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](http://php.net/manual/en/function.array-walk.php), 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
)
```

* * *

**In Routing**

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()`](http://www.php.net/manual/en/closure.bind.php) or [`bindTo`](http://www.php.net/manual/en/closure.bindto.php) 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:

```
$myClass = $getMyClass();
```

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.

 ![](http://feeds.feedburner.com/~r/codeinphpfeed/~4/QI9f2vnPtWE)