Closures and anonymous are something I found hard to learn in the whole PHP ecosystem, not because I am probably nut but because there isn't any good and well extended explanation of what exactly they are and how they can be used.
I have decided to dig and see if I can understand what exactly PHP closures are. Here I will be sharing with you how I did that and what I found. While my method might not scientific to some of you, I have tried a personal procedure which I did not take much time to polish.
What is an anonymous function?
A nameless function. An anonymous function looks like this:
function($x){
return $x * 2;
}
A normal function:
function timesTwo($x){
return $x * 2;
}
Contrary to normal functions, anonymous function doesn't have a name.
Now imagine if you want to use the anonymous function, how to you do that? basically(can be used in firt-class functions) there is no way to do that. So, to help do that a name binding is implemented allowing the whole anonymous function to be stored in a variable
. When that is done, that variable
becomes what is called a Closure.
What is a closure in PHP?
A class which(type) is used to represent anonymous function. This may sound very strange, in PHP there is a built-in class called Closure. When an anonymous function is created, its type is automatically object(Closure)
. Remember PHP dynamic typing. That's why in practice a Closure is an Anonymous function.
To prove that try this:
var_dump(function($x){
return $x * 2;
});
A variable containing an anonymous function
When an anonymous function is bound to a variable, that variable becomes a Closure class object, therefore a Closure/anonymous function too.
On the way of understanding this
First, try to create an object/instance of the class Closure.
$closure = new Closure();
We get this:
PHP Catchable fatal error: Instantiation of 'Closure' is not allowed
This is explained by this:
- The class Closure is not meant to be instanciated; its constructor is set to
private
. - The class returns nothing and has no parameters.
Some fact about that class
- It has only 5 methods :
__construct()
,__invoke()
,bindTo()
,call()
,bind()
- The
__construct()
method exists only to disallow the instanciation of the class - It's definitely not an interface
- The class is final
Small digging
We don't need to create an instance of Closure since PHP does that every time a function is created without a name, so I can now do:
function()
{
return true;
}
The problem how to use it like that ??
Solution, create a variable and store the function in, then by using the variable we're calling the function:
$closureFunction = function()
{
return true;
}; //never forget this semi-colon
Now since it's(looks) like a variable, we should be able to use it in many ways like by echoing it, using it as a function parameter, or a class property, etc.
--With echo()
echo $closureFunction; // PHP Catchable fatal error: Object of class Closure could not be converted to string;
--As function
echo test($closureFunction); //PHP Catchable fatal error: Object of class Closure could not be converted to string
No matter where you try to echo
it, you will always get this error. To prove that let's var_dump
it and see what we're trying to echo:
var_dump($closureFunction);
var_dump(test($closureFunction));
Result:
object(Closure)#1 (0) { }
object(Closure)#1 (0) { }
The variable containing our nameless
function contains actually an object of Closure type.
What happened, How the function got converted into an object?
Before I answer, let's dig further by setting a parameter to the function:
$closureFunction = function($var)
{
return $var;
};
function test($var)
{
return $var;
}
var_dump($closureFunction); // object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
var_dump($closureFunction('ok')); // string(2) "ok"
echo($closureFunction('ok')); // ok
var_dump(test($closureFunction)); //object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
var_dump(test($closureFunction('ok'))); // string(2) "ok"
var_dump(test($closureFunction($closureFunction))); // object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
From here so far:
- the
nameless
function is in the variable - we can use it anywhere as a variable can be used except echoing it
- the function becomes an object of Closure class
Explanation of the magic:
-
The fact that the Closure class implements
__invoke
means we can call its instances like a function call, like$var()
.If this:
$var = function(){};
is an object of Closure it allows us to use$var
with a parameter like$var($parameter)
. In that case the class is called a callable. -
Closures are considered first-class value types, just like a
string
orinteger
. This is actually the secret. Closure is a type defined in PHP engine as a type and you don't see exactly when they are generated.
What's the use?
Their use depends mostly on your use case and needs. Nevertheless you can use them as:
-- Callables/Callback functions like this:
$items = [1, 2];
$closure = function($x, $y){
echo __FUNCTION__, " got $x and $y";
};
call_user_func_array ($closure , $items );
-- Variable inheritance like this:
$msg = 'Hello';
$closure = function () use ($msg) {
var_dump($msg);
};
$closure();
-- Variable assignment
$eat = function($food){
echo "I am eating some ", $food."<br>";
};
$eat('Bananas');
$eat('Apples');
-- to attache state like this:
function brand($name) {
return function ($slogan) use ($name){
return sprintf('%s : %s', $name, $slogan);
};
}
$brand = brand('Dell');
print $brand('The power to do more.');
-- Recursion
$recursive = function () use (&$recursive){
return $recursive;
} ;
print_r($recursive());
Some practical use cases
- In most modern frameworks, closures are used for routing
- Closure are also used in developing shopping carts
Conclusion
This was an exploration of PHP closures. I hope you have been close enough to them. Anonymous functions are always tricky to understand and in their use.
What you should know now is that every time you have a case/problem, just remember and ask yourself if Closures could be of great help. You will be surprised to use how they will make your life easy.
I also recognize I could not say/explain all. If you have a plus, please add it under this tutorial as a comment. Thanks for reading.
Last updated 2024-01-11 UTC