An Intro to Closures in PHP

Although closures are an integral part of Functional Programming, they can be useful in some other paradigms such as OOP and in this tutorial I am going to show what an anonymous function or closure is and how we can write one in PHP programming language.

In a nutshell, closure is an anonymous function because it does not have any name attached to it. Basically, there isn't much difference between a normal function and an anonymous function except the latter doesn't have a name. For example, in the following code block, our closure name is $closure which is to print "Hello World" in the output:

<?php
$closure = function () {
    echo "Hello World";
};
$closure();

As you can see, after the variable name comes the = sign then the function keyword followed by () and {} and at the end comes a ;. Inside the curly braces, we write the actual function code which in this case is to print "Hello World". An important note that needs to be taken into consideration is that as this function is assigned to a variable, after the closing curly brace we need to add a semicolon. To call this anonymous function, we just need to write the name of the variable followed by () because we are dealing with a function and in the output, we will have:

Hello World

When we are working with closures in PHP, we have to know a couple of points about scope. When we are talking about scope, we mean the part of our codebase that a variable is defined for and is also valid. To make it clearer, let's change the previous example:

<?php
$variable = "Hello World";
$closure = function () {
    echo $variable;
};
$closure();

As you can see, a variable called $variable is created outside the closure and then used inside it but if we run this piece of code, we will see nothing in the output because a closure has its own scope and it knows nothing from the outside world! The response to a question such as "Can we pass a variable to a closure?" is "Yes" and we can do it as follows:

<?php
$variable = "Hello World";
$closure = function ($input) {
    echo $input;
};
$closure($variable);

But sometimes we don't want to pass a variable to our closure instead we want our closure to have access to scope in the outside. In these situations, we can modify the previous closure like this:

<?php
$variable = "Hello World";
$closure = function () use ($variable) {
    echo $variable;
};
$closure();

By using the use keyword, we can give our closure the ability to access the scope outside it. In other words, we can import a variable into the closure.

Something to bear in mind regarding the use keyword is that variables passed to closure are all pass by value not by reference. In other words, if the closure changes the value of a variable, those changes are not visible in the actual variable. For example:

<?php
$variable = "Hello World";
$closure = function () use ($variable) {
    echo $variable . " Updated";
};
$closure();
echo "\n";
echo $variable;

First, take a look at the output then we explain the code:

Hello World Updated
Hello World

The first output is related to the closure which has updated the content of $variable and the latter is the actual value of $variable which isn't affected by the closure.

In the following example, we will see a more real-world use case for closures. In fact, by using an anonymous function, we are going to select the even numbers out of an array of numbers including both odd and even numbers:

<?php
$array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$resultset = array_filter($array, function ($item) {
    return ($item % 2 == 0);
});
print_r($resultset);

First, let's see what the output is then I'll explain the code:

Array
(
    [1] => 2
    [3] => 4
    [5] => 6
    [7] => 8
    [9] => 10
)

As you can see, the output is just even numbers found in the $array array. In this example, we have used array_filter() built-in function which accepts an array to iterate over and a callback which in this case is a closure that will return true for all even numbers. Our closure accepts an input called $item which is the current value of $array at each particular index and line 4 says that return true for all even numbers. We can also extract this anonymous function out to make our code cleaner as well:

<?php
$array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$closure = function ($item) {
    return ($item % 2 == 0);
};
$resultset = array_filter($array, $closure);
print_r($resultset);

In fact, we have created an anonymous function called $closure which equals to the closure we have been using and passed it as the second argument to the array_filter() function.

by Behzad Moradi on 2019-08-10

Login to add your comment