on Expert Tutorials

Anonymous or lambda functions in PHP

2 comments
lambda
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

Wikipedia says: In computing, an anonymous function is a function (or a subroutine) defined, and possibly called, without being bound to an identifier.

Sounds pretty complicated.

I will start with showing some interesting example of, so called, variable functions in PHP. It means that if we append parenthesis to a variable, then PHP will look for a function with the same name as to whatever the variable evaluates to and try to execute it.

OMG, this really sound complicated. Let me show you:

function Test($var) {
    echo "This is $var";
}

This is very simple function. We can now call this function indirectly using a variable which value is the same as the function name:

$f = "Test";
$f("variable function");

The above code will output This is variable function. This PHP functionality is the reason that using double quotes is slower then single quotes, as you can see in my PHP Mythbusters article.

We can use it in OOP as well, as seen in the php.net example:

class Foo
{
    function Variable()
    {
        $name = 'Bar';
        $this->$name(); // This calls the Bar() method
    }
    
    function Bar()
    {
        echo "This is Bar";
    }
}

$foo = new Foo();
$funcname = "Variable";
$foo->$funcname();  // This calls $foo->Variable()

This is an interesting concept that can be used to implement callbacks, function tables, and so forth.

Now let me try to explain an anonymous function. We have this code:

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });

function ($v) { return $v > 2; } is the lambda function definition. We can even store it in a variable, so it can be reusable:

$max = function ($v) { return $v > 2; };
 
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);

Now, what if you want to change the maximum number allowed in the filtered array? You would have to write another lambda function or create a closure (PHP 5.3):

$max_comp = function ($max) {
  return function ($v) use ($max) { return $v > $max; };
};
 
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));

A closure is a function that is evaluated in its own environment, which has one or more bound variables that can be accessed when the function is called. They come from the functional programming world, where there are a number of concepts in play. Closures are like lambda functions, but smarter in the sense that they have the ability to interact with variables from the outside environment of where the closure is defined.

Here is a simpler example of PHP closure:

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

$closure();

Variables to be imported from the outside environment are specified in the use clause of the closure function definition. By default, they are passed by value, meaning that if we would update the value passed within the closure function definition, it would not update the outside value. We can, however, do this by prefacing the variable with the & operator, which is used in function definitions to indicate passing by reference. Example:

$x = 1
$closure = function() use (&$x) { ++$x; }

echo $x . "<br />";
$closure();
echo $x . "<br />";
$closure();
echo $x . "<br />";

You see the closure is using the outside variable $x and incrementing it each time the closure is called. We can mix variables passed by value and by reference easily within the use clause, and they will be handled without any problem.

As we saw in the examples for lambda functions, one of the most obvious uses for closures is in the few PHP functions that accept a callback function as a parameter. Closures, however, can be useful in any context where we need to encapsulate logic inside its own scope.

The real beauty of closures is that it avoids polluting the global namespace with a function that is used only once. As soon as the variable falls out of scope it, and the closure contained in it is destroyed.

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon