Mar 25, 2013
Table of contents:
Lambdas and Closures are relatively new additions to PHP after shipping with version 5.3. Both offer some new functionality and the ability to refactor old code to be cleaner and more intuitive. However, I think many developers are unaware of Lambdas and Closures or confused about what they actually do.
In this post I will be explaining Lambdas and Closures, give you some example code to show their usage and give you a real life example of them in action to show you their prevalence in modern PHP.
A Lambda is an anonymous function that can be assigned to a variable or passed to another function as an argument. If you are familiar with other programming languages like Javascript or Ruby, you will be very familiar with anonymous functions.
An anonymous function is simply a function with no name.
For example, to create a regular function, you might write something like this:
// Regular function
function greeting()
{
return "Hello world";
}
You can then simply call this function like this:
echo greeting();
// Returns "Hello world"
An anonymous function has no name so you would define it like this:
// Anonymous function
function ()
{
return "Hello world";
}
Because the function has no name, you can’t call it like a regular function. Instead you must either assign it to a variable or pass it to another function as an argument.
// Anonymous function
// assigned to variable
$greeting = function () {
return "Hello world";
}
// Call function
echo $greeting();
// Returns "Hello world"
To so use the anonymous function, we assign it to a variable and then call that variable as a function.
You could also pass the function to another function, like this:
// Pass Lambda to function
function shout($message)
{
echo $message();
}
// Call function
shout(function () {
return "Hello world";
});
Lambdas are useful because they are throw away functions that you can use once. Often, you will need a function to do a job, but it doesn’t make sense to have it within the global scope or to even make it available as part of your code. Instead of having a function used once and then left lying around, you can use a Lambda instead.
Of course, you have been able to use the create_function function in PHP for a while now. This basically does the same job.
// Use create_function
$greeting = create_function('echo "Hello World!";');
// Call function
$greeting();
A Closure is essentially the same as a Lambda apart from it can access variables outside the scope that it was created.
For example:
// Create a user
$user = "Philip";
// Create a Closure
$greeting = function () use ($user) {
echo "Hello $user";
};
// Greet the user
$greeting(); // Returns "Hello Philip"
As you can see above, the Closure is able to access the $user variable. because it was declared in the use clause of the Closure function definition.
If you were to alter the $user variable within the Closure, it would not effect the original variable. To update the original variable, we can append an ampersand. An ampersand before a variable means this is a reference and so the original variable is also updated.
For example:
// Set counter
$i = 0;
// Increase counter within the scope
// of the function
$closure = function () use ($i) {
$i++;
};
// Run the function
$closure();
// The global count hasn't changed
echo $i; // Returns 0
// Reset count
$i = 0;
// Increase counter within the scope
// of the function but pass it as a reference
$closure = function () use (&$i) {
$i++;
};
// Run the function
$closure();
// The global count has increased
echo $i; // Returns 1
Closures are also useful when using PHP functions that accept a callback function like array_map, array_filter, array_reduce or array_walk.
The array_walk function takes an array and runs it through the callback function.
// An array of names
$users = ["John", "Jane", "Sally", "Philip"];
// Pass the array to array_walk
array_walk($users, function ($name) {
echo "Hello $name<br>";
});
// Returns
// -> Hello John
// -> Hello Jane
// -> ..
Again, you can access variables outside the scope of the Closure by using the use clause:
// Set a multiplier
$multiplier = 3;
// Create a list of numbers
$numbers = [1, 2, 3, 4];
// Use array_walk to iterate
// through the list and multiply
array_walk($numbers, function ($number) use ($multiplier) {
echo $number * $multiplier;
});
In the example above, it probably wouldn’t make sense to create a function to just multiply two numbers together. If you were to create function to do a job like this, then come back to the code a while later you will probably be thinking why did you bother create a globally accessible function only to be used once? By using a Closure as the callback, we can use the function once and then forget about it.
So we’ve established that Lambdas and Closures are anonymous functions that can be used as throw away bits of functionality that don’t pollute the global namespace and are good to use as part of a callback.
A popular example of the use of these types of functions is in routing requests within modern frameworks. Laravel for example, allows you to do the following:
Route::get("user/(:any)", function ($name) {
return "Hello " . $name;
});
The code above simply matches a URL like /user/philip and returns a greeting.
This is a very basic example, but it highlights how a Closure can be utilised in a very useful situation.
So hopefully that was a good explanation of Lambdas and Closures.
Lambdas and Closures seem like two very deep Computer Science terms if you are a newbie programmer. However, it’s actually not that complicated at all. Both Lambdas and Closures are simply anonymous functions that are useful for one offs or where it doesn’t make sense to define a function.
Lambdas and Closures are fairly new to PHP and they don’t follow exactly the same usage as in other languages. If you are at all familiar with Javascript, you will see anonymous functions used a lot. In particular, you will see a lot of good examples in jQuery. Once you can recognise the pattern, it makes reading code a lot easier because you not only understand what is going on, but also understand why it was written like that in the first place and what the developer was trying to achieve through her decisions.