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. Our users don't see ads
  2. Or, Sign up if you don't have an account yet
  3. Or, disable your adblocker by doing this:
    • Click on the adblocker 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