In my opinion this is consistent with the fact that PHP has no
block-scoped variables. The situation is similar with the one in JavaScript.
In JavaScript the problem has been solved by Mozilla with so-called let
definitions[1], which are block-scoped.
1:
https://developer.mozilla.org/en/New_in_JavaScript_1.7#Block_scope_with_let
On 3/1/10 2:33 PM, mathieu.suen wrote:
Hi,
I am proposing a comparison between PHP closure with lisp one.
First thing to compare is how scope are capture:
Suppose I want to create a function that add.
The common idiom to do it in lisp is:
(defun adder (x) #'(lambda (y) (+ x y)))
Then if I want the add3 method you can do:
(setf (symbol-function 'add3) (adder 3))
(add3 4) => 7
Now let reproduce that in php:
$adder = function ($x) {return function ($y) use($x) {return $y + $x;};};
$add3 = $adder(3);
echo $add3(4); => 7
Every thing is fine but let change the adder into a counter :
In lisp you could do:
(let ((sum 0))
(defun counter () (setf sum (1+ sum))))
(counter) => 1
(counter) => 2
(counter) => 3 ...
In other to have the same behavior in PHP you first need to transform
the let into a lambda which make no difference in lisp:
(funcall #'(lambda (sum) (defun counter () (setf sum (1+ sum)))) 0)
Now we are ready to do it in PHP.
$createCounter = function ($sum) { return function () use ($sum) {return
++$sum;};};
$counter = $createCounter(0);
$counter(); => 1
$counter(); => 1
$counter(); => 1
...
So that's not the expected behavior.
In oder to have the expected behavior you need to add & in front of $sum.
But & is kind of evil since it mimics dynamic scoping:
$array = array(1, 2, 3);
foreach($array as $pos)
{
$adders[] = function ($x) use (&$pos) { return $pos+ $x;};
}
foreach($adders as $addIt)
{
echo $addIt(5);
}
Thanks for your attention
-- Mathieu Suen
--
Ionut G. Stan
I'm under construction | http://blog.igstan.ro/
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php