note 95994 deleted from functions.anonymous by danbrown
| From: | danbrown@php.net | Date: | Tue, 02 Feb 2010 16:00:19 +0000 |
| Subject: | note 95994 deleted from functions.anonymous by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-165600@lists.php.net to get a copy of this message | ||
Note Submitter: bishamon
----
Someone needs to rewrite the documentation for this section. An anonymous function IS NOT the same
thing as a closure. Anonymous functions are needed to implement closures, but they're not the
same thing.
A closure is a function that has it's scope bound to another scope. Typically, the other scope
is the local scope of another function. The closure then is a function that's nested inside
another function but still has access to the "outer" function's variables.
To put it another way, a closure is an anonymous function, but an anonymous function is not always a
closure.
Here's an example of how closures work:
<?php
function outer () {
$var = 0;
return function () use (&$var) {
$var++;
var_dump($var);
};
}
$inner = outer();
$inner(); // int 1
$inner(); // int 2
$inner(); // int 3
?>
Several things are happening here, so let's look at them:
1) The return value of outer() is a function. This is where the anonymous function comes into play.
2) The function returned by outer() has access to outer()'s variable $var through the use()
clause. Furthermore, it can modify that variable since it is accessed as a reference.
3) The when outer() is called, the anonymous function it returns is stored in the variable $inner.
Even though outer() is finished running, because a reference to the function defined inside it still
exists, the variables (or state) of outer() is maintained. This is what creates the closure. As long
as $inner exists, $var will also exist and be accessible by the function in $inner.
4) When $inner() is called, the code in the anonymous function executes. It still has access to the
$var variable defined in outer().
A function can also return a closure through its parameters by using a reference. This allows you to
return multiple closure functions from a function.
Here's an example to show how powerful closures are:
<?php
function counter_factory(&$add, &$sub) {
$var = 0;
$add = function ($i = 1) use (&$var) {
$var += $i;
var_dump($var);
};
$sub = function ($i = 1) use (&$var) {
$var -= $i;
var_dump($var);
};
}
counter_factory($x_up, $x_down); // a closure over $var is created
counter_factory($y_up, $y_down); // a closure over a different $var is created
// These work with the first closure
$x_up(); // int 1
$x_up(3); // int 4
$x_down(2); // int 2
$x_up(); // int 3
// These work with the second closure
$y_up(); // int 1
$y_down(2); // int -1
$y_up(); // int 0
// The statements above could be interleaved and still get the same results.
?>
The magic that happens here is that each time counter_factory() is called, a new closure (a scope
that includes $var and the two functions) is created. The returned functions have access to the $var
where they were created. They then act as independent counters.