note 97296 deleted from functions.anonymous by cmb
| From: | cmb@php.net | Date: | Sun, 11 Aug 2019 11:05:41 +0000 |
| Subject: | note 97296 deleted from functions.anonymous by cmb | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-211839@lists.php.net to get a copy of this message | ||
Note Submitter: Hayley Watson
----
In the code
<?php
function new_counter()
{
$counter = mt_rand();
return function()use(&$counter)
{
return ++$counter;
};
}
$t1 = new_counter();
$t2 = new_counter();
echo $t1(),"\n";
echo $t1(),"\n";
echo $t2(),"\n";
echo $t2(),"\n";
echo $t1(),"\n";
echo $t1(),"\n";
?>
The variable $counter is local to new_counter() and is used by reference by the returned lambda
function.
Because $counter is not static, a new variable is created each time new_counter() is called.
But because the lambda function uses a REFERENCE to the $counter variable - and not a new local
variable with a copy of the value $counter had when the lambda function was constructed - the
$counter variable created when new_counter() ran still exists (because a reference to it still
exists).
Every lambda function has a variable reference "hardwired" into it. That variable
therefore persists across calls to the lambda function - rather like a static variable.
But that variable is only LOCAL to the new_counter() function that created it. As soon as
new_counter() returns, it gives up its reference to $counter. When new_counter() is called again, it
gets allocated a NEW $counter variable and gives a reference to THAT variable to the lambda function
it constructs.
So the lambda functions in $t1 and $t2 each have their OWN $counter variable - separate from the
other's, which persists from one call to the next.
The effect is very similar to declaring and initialising $counter as static within the lambda
function - and then it doesn't need to use anything from new_counter() - but you can't
initialise a static variable with a function call like mt_rand()!
Pending a decision on what it should mean, $this is not currently (as of 5.3.2) usable within
anonymous functions.
There are roughly two positions (plus attempts at compromise), that can be called "early"
and "late".
Early: $this refers to the object in whose scope the anonymous function is constructed.
<?php
class Creator
{
public function make_anonymous()
{
return function()
{
return $this;
};
}
}
class Caller
{
public $p;
public function call_anonymous($f)
{
$this->p = $f();
}
}
$alpha = new Creator;
$omega = new Caller;
$omega->call_anonymous($alpha->create_anonymous());
// $omega->p === $alpha
?>
Late: $this refers to the object in whose scope the anonymous function is called.
<?php
class Creator
{
public function make_anonymous()
{
return function()
{
return $this;
};
}
}
class Caller
{
public $p;
public function call_anonymous($f)
{
$this->p = $f();
}
}
$alpha = new Creator;
$omega = new Caller;
$omega->call_anonymous($alpha->create_anonymous());
// $omega->p === $omega
?>
So until this is cleared up, $this won't work in an anonymous function. (Personally, I favour
the early method; otherwise the anonymous function - and therefore its Creator - has access to all
of the Caller's private properties.)