Why and How to Use Anonymous Functions in PHP

Why use anonymous function?

I would say that anonymous functions show their beauty when there is good library classes/functions that use them. They are not that sexy by themselves. In the world of .net there is technology called LINQ that makes huge use of then in very idiomatic manner. Now back to PHP.

First example, sort:

uasort($array, function($a, $b) { return($a > $b); });

You can specify complex logic for sorting:

uasort($array, function($a, $b) { return($a->Age > $b->Age); });

Another example:

$data = array( 
array('id' => 1, 'name' => 'Bob', 'position' => 'Clerk'),
array('id' => 2, 'name' => 'Alan', 'position' => 'Manager'),
array('id' => 3, 'name' => 'James', 'position' => 'Director')
);

$names = array_map(
function($person) { return $person['name']; },
$data
);

You see how nicely you can produce array of names.

Last one:

array_reduce(
array_filter($array, function($val) { return $val % 2 == 0; },
function($reduced, $value) { return $reduced*$value; }
)

It calculates product of even numbers.

Some philosophy. What is function? A unit of functionality that can be invoked and unit of code reuse. Sometimes you need only the first part: ability to invoke and do actions, but you don't want to reuse it at all and even make it visible to other parts of code. That's what anonymous functions essentially do.

Why and how do you use anonymous functions in PHP?

Anonymous functions are useful when using functions that require a callback function like array_filter or array_map do:

$arr = range(0, 10);
$arr_even = array_filter($arr, function($val) { return $val % 2 == 0; });
$arr_square = array_map(function($val) { return $val * $val; }, $arr);

Otherwise you would need to define a function that you possibly only use once:

function isEven($val) { return $val % 2 == 0; }
$arr_even = array_filter($arr, 'isEven');
function square($val) { return $val * $val; }
$arr_square = array_map('square', $arr);

PHP: Is there a difference in passing a variable to anonymous function, and using closure function?

The closure function is useful when you don't have control over the arguments that are being passed. For instance, when you use array_map you can't add an additional parameter, it just receives the array elements. You can use the closure to access additional variables.

$string = "foo";
$array = ["abc", "def"];
$new_array = array_map(function($x) use ($string) {
return $string . $x;
}, $array);

How to use anonymous function php

You shouldn't use create_function(). create_function() uses eval(). eval() is evil.

On a more serious note, eval() (and thus create_function()) has big security issues. If you're on PHP 5.3 or higher, you should use native anonymous functions instead, in this case:

$callback = function($matches) {
return strtoupper($matches[1]);
}

For reference: Anonymous functions.

Note that create_function has been deprecated as of PHP 7.2.

Use of Anonymous Functions in PHP

The function itself has no name, as you show in your example you can still create a "real" function with the "same name". They're usually used like this as callbacks, which may seem more "anonymous":

foo(function ($bar) { ... });

How do you use an anonymous function inside a class in PHP?

The fact that you call greet makes PHP treat it like a function and not a property. You can have the same name for both a property and method in PHP, so the distinction is relevant.

PHP 7+

In PHP7 the __call() method is no longer needed to call closures bound to properties, because of Uniform Variable Syntax. This will allow you to add parentheses around any code, just like you do in arithmetics.

class Model
{
public $greet;
function __construct()
{
$this->greet = function($name)
{
printf("Hello %s\r\n", $name);
};
}
}

$test = new Model();
($test->greet)('johnny');

PHP 5

What you can doe as a workaround is use the __call() magic method. It will catch the call to the undefined greet method.

class Model
{
public $greet;
function __construct()
{
$this->greet = function($name)
{
printf("Hello %s\r\n", $name);
};
}

function __call($method, $args)
{
if (isset($this->$method) && $this->$method instanceof \Closure) {
return call_user_func_array($this->$method, $args);
}

trigger_error("Call to undefined method " . get_called_class() . '::' . $method, E_USER_ERROR);
}
}

$test = new Model();
$test->greet('johnny');

In PHP, what is a closure and why does it use the use identifier?

This is how PHP expresses a closure. This is not evil at all and in fact it is quite powerful and useful.

Basically what this means is that you are allowing the anonymous function to "capture" local variables (in this case, $tax and a reference to $total) outside of it scope and preserve their values (or in the case of $total the reference to $total itself) as state within the anonymous function itself.

Using `$this` in an anonymous function in PHP pre 5.4.0

It will fail when you try to call a protected or private method on it, because using it that way counts as calling from the outside. There is no way to work around this in 5.3 as far as I know, but come PHP 5.4, it will work as expected, out of the box:

class Hello {

private $message = "Hello world\n";

public function createClosure() {
return function() {
echo $this->message;
};
}

}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$helloPrinter(); // outputs "Hello world"

Even more, you will be able to change what $this points to at runtime, for anonymus functions (closure rebinding):

class Hello {

private $message = "Hello world\n";

public function createClosure() {
return function() {
echo $this->message;
};
}

}

class Bye {

private $message = "Bye world\n";

}

$hello = new Hello();
$helloPrinter = $hello->createClosure();

$bye = new Bye();
$byePrinter = $helloPrinter->bindTo($bye, $bye);
$byePrinter(); // outputs "Bye world"

Effectively, anonymus functions will have a bindTo() method, where the first parameter can be used to specify what $this points to, and the second parameter controls what should the visibility level be. If you omit the second parameter, the visibility will be like calling from the "outside", eg. only public properties can be accessed. Also make note of the way bindTo works, it does not modify the original function, it returns a new one.

PHP variables in anonymous functions

Yes, use a closure:

functionName($someArgument, function() use(&$variable) {
$variable = "something";
});

Note that in order for you to be able to modify $variable and retrieve the modified value outside of the scope of the anonymous function, it must be referenced in the closure using &.



Related Topics



Leave a reply



Submit