It seems like you are using an ad blocker. To enhance your experience and support our website, please consider:

  1. Signing in to disable ads on our site.
  2. Sign up if you don't have an account yet.
  3. Or, disable your ad blocker by doing this:
    • Click on the ad blocker icon in your browser's toolbar.
    • Select "Pause on this site" or a similar option for lancecourse.com.

A takeover of PHP Closure and anonymous functions

By zooboole

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 or integer. 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