We've been daydreaming about the ability to do something like this in
PHP:
$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabetically
In the past, people have been told to use the travesty that is
create_function()
to emulate this kind of behavior, well, it turns
out to be a minor patch to the parser to pull that into the core.
You can find my prototype patch at http://pastebin.ca/400871 (against
PHP_5_2)
The way it works is by making the expression:
function() {}
evaluate to the (generated) name of the anonymous function.
$foo = function() {};
sets $foo to a string like "__zend_anon_1", which can then be passed
around as a callback name, just like the way that create_function()
works, except that you don't need to use crazy quoting to declare any
kind of moderately complex function.
There's one minor flaw in my implementation for ZTS enabled systems
(just need to move the anon function counter into CG() to solve that.
So, the question is, do we want this in PHP?
--Wez.
So, the question is, do we want this in PHP?
yes, please.
Jan
I found another flaw; when used in a loop it keeps trying to declare
the same function over and over. I think this is because the
ZEND_DECLARE_FUNCTION opcode is emitted as part of the arg list
building op sequence.
I'm poking to find an elegant way to fix that.
--Wez.
You can find my prototype patch at http://pastebin.ca/400871
(against PHP_5_2)
There's one minor flaw in my implementation for ZTS enabled systems
(just need to move the anon function counter into CG() to solve that.
So, the question is, do we want this in PHP?
yes, please.
Anonymous function declaration is one of the things I've always loved in
Ruby and JavaScript - I for one would love to see this in php.
-- Jim R. Wilson (jimbojw)
I found another flaw; when used in a loop it keeps trying to declare
the same function over and over. I think this is because the
ZEND_DECLARE_FUNCTION opcode is emitted as part of the arg list
building op sequence.I'm poking to find an elegant way to fix that.
--Wez.
You can find my prototype patch at http://pastebin.ca/400871
(against PHP_5_2)There's one minor flaw in my implementation for ZTS enabled systems
(just need to move the anon function counter into CG() to solve that.
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it
doesn't seem too far wrong.
--Wez.
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it
doesn't seem too far wrong.
-
-
if (!memcmp(opline-
-
op2.u.constant.value.str.val, "_zend_anon", sizeof
("_zend_anon")-1)) {
Pardon my nitpicking, but shouldn't this be:
-
-
if (!memcmp(opline-
-
op2.u.constant.value.str.val, "_zend_anon", strlen
("_zend_anon")-1)) {
Also, a strong +1 for this patch, I'd love to see this support in PHP.
-- Gwynne, Daughter of the Code
"This whole world is an asylum for the incurable."
Your nitpicking happens to be wrong ;-)
sizeof("string constant") is the "same" as strlen("string constant")
+1, but is resolved at compile time, so we use sizeof("string
constant")-1 to get a compile time evaluated strlen()
. This trick is
used throughout the PHP internals.
--Wez.
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it
doesn't seem too far wrong.
if (!memcmp(opline-
op2.u.constant.value.str.val, "_zend_anon", sizeof
("_zend_anon")-1)) {Pardon my nitpicking, but shouldn't this be:
if (!memcmp(opline-
op2.u.constant.value.str.val, "_zend_anon", strlen
("_zend_anon")-1)) {Also, a strong +1 for this patch, I'd love to see this support in PHP.
-- Gwynne, Daughter of the Code
"This whole world is an asylum for the incurable."
Your nitpicking happens to be wrong ;-)
sizeof("string constant") is the "same" as strlen("string constant")
+1, but is resolved at compile time, so we use sizeof("string
constant")-1 to get a compile time evaluatedstrlen()
. This trick
is used throughout the PHP internals.
Ah. I've never seen it used that way before; I apologize for my
ignorance :). In my experience, sizeof()
on a character constant
would evaluate as sizeof( const char * const ).
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it
doesn't seem too far wrong.
if (!memcmp(opline-
op2.u.constant.value.str.val, "_zend_anon", sizeof
("_zend_anon")-1)) {Pardon my nitpicking, but shouldn't this be:
if (!memcmp(opline-
op2.u.constant.value.str.val, "_zend_anon", strlen
("_zend_anon")-1)) {Also, a strong +1 for this patch, I'd love to see this support in
PHP.
-- Gwynne, Daughter of the Code
"This whole world is an asylum for the incurable."
Hello Gwynne,
Monday, March 19, 2007, 3:13:28 AM, you wrote:
Your nitpicking happens to be wrong ;-)
sizeof("string constant") is the "same" as strlen("string constant")
+1, but is resolved at compile time, so we use sizeof("string
constant")-1 to get a compile time evaluatedstrlen()
. This trick
is used throughout the PHP internals.
Ah. I've never seen it used that way before; I apologize for my
ignorance :). In my experience,sizeof()
on a character constant
would evaluate as sizeof( const char * const ).
Actually it is not a "const char *" here. Instead the language generates
a "const char[]" which works asexpected.
Best regards,
Marcus
Hello Wez,
interesting solution. Nice work:-)
Monday, March 19, 2007, 1:48:31 AM, you wrote:
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it
doesn't seem too far wrong.
--Wez.
Best regards,
Marcus
Hey, thanks, I was researching this exact same thing. You make it appear much
easier than it is. You've just saved me many months, weeks, and hours trying to
figure out how to mess with the internals of the Zend Engine. For that, I am
most grateful.
Also, I would love to see this in PHP, at the very least it would negate the
argument of those who say PHP doesn't support anonymous functions.
Jacob Santos
Updated patch at http://pastebin.ca/400952
Not 100% sure if my hack in zend_compile.c is righteous, but it doesn't
seem too far wrong.--Wez.
Also, I would love to see this in PHP, at the very least it would negate
the argument of those who say PHP doesn't support anonymous functions.
This argument is false in any case, since create_function exists and
this implementation is other way to write create_function :)
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Updated patch at http://pastebin.ca/400952
This is interesting. I'm not sure I'll ever use it (I prefer named
functions), but it's a purely optional and folks seem to want
something like this.
One comment on the patch itself:
static unsigned int anon_count;
I think you should provide an initial value (0?) for this static
counter. Also, you should protect against wrap-around (which, while
improbably, is possible).
Alternatively, you could change the anonymous function naming scheme
to something like __zend_anon_FILE_LINE_COLUMN, but that could be an
unnecessary waste of string memory.
--
Jon Parise (jon of php.net) :: The PHP Project (http://www.php.net/)
I found another flaw; when used in a loop it keeps trying to declare
the same function over and over. I think this is because the
ZEND_DECLARE_FUNCTION opcode is emitted as part of the arg list
building op sequence.I'm poking to find an elegant way to fix that.
Would the function body/arglist be allowed to change based on the loop
data? [shudder]
It's starting to sound like Lisp :-)
Though I guess if you need anonymous functions, you probably need them
with varying bodies as well.
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabetically
What happens if you do this:
$data = array("zoo", "orange", "car", "lemon", "apple");
$rev = 1;
usort($data, function($a, $b) { return $rev?strcmp($a, $b):!strcmp($a,
$b); });
var_dump($data); # data is sorted alphabetically
This works in Javascript (probably Ruby too), but quite hard to make
work in PHP because $rev is in different scope.
Moreover, would it mean that this:
$f = function($a, $b) { return $rev?strcmp($a, $b):!strcmp($a, $b); }
would work too? Keeping right value of $rev?
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I didn't make it do anything fancy with scoping; it would make the
implementation more complicated, and wouldn't fit so well with the
way that scoping works in PHP, in that you need to explicitly
reference the global scope to "break out" of your function scope.
It would be cool if the lexical scope was inherited, but maybe not
cool enough to warrant making it work :)
--Wez.
$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabeticallyWhat happens if you do this:
$data = array("zoo", "orange", "car", "lemon", "apple");
$rev = 1;
usort($data, function($a, $b) { return $rev?strcmp($a, $b):!strcmp
($a, $b); });
var_dump($data); # data is sorted alphabeticallyThis works in Javascript (probably Ruby too), but quite hard to
make work in PHP because $rev is in different scope.
Moreover, would it mean that this:
$f = function($a, $b) { return $rev?strcmp($a, $b):!strcmp($a, $b); }
would work too? Keeping right value of $rev?Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I didn't make it do anything fancy with scoping; it would make the
implementation more complicated, and wouldn't fit so well with the way
that scoping works in PHP, in that you need to explicitly reference the
global scope to "break out" of your function scope.It would be cool if the lexical scope was inherited, but maybe not cool
enough to warrant making it work :)
Well, making it work makes this thing closure. Otherwise it's just a
nice way to save a couple of keystrokes :) Not to diminish your work,
but there's a danger people would think it is closure because it looks
like one (i.e., in other languages closures look exactly this way, e.g.
Javascript).
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Stanislav Malyshev wrote:
Well, making it work makes this thing closure. Otherwise it's just a
nice way to save a couple of keystrokes :) Not to diminish your work,
but there's a danger people would think it is closure because it looks
like one (i.e., in other languages closures look exactly this way, e.g.
Javascript).
Wez' proposal sounds very intriguing. At the same time I wouldn't try to
add closures to PHP as while they might be a mighty concept they are
also complicated and have a high WTF factor IMHO. When I first started
doing more complex things in Javascript I was bitten more than once by
closures: Sometimes they did what I expected and sometimes they didn't
(e.g. when using 'this').
But I agree that it would be great to being able to pass context to the
generated function, preferably not via a global variable.
One possible solution would be to generate the function as a method of
the current object and expose this so something like
usort($data, function($a, $b) { return $this->cmp($a, $b); });
could be used.
- Chris
Well, making it work makes this thing closure. Otherwise it's just a
nice way to save a couple of keystrokes :) Not to diminish your work,
but there's a danger people would think it is closure because it looks
like one (i.e., in other languages closures look exactly this way, e.g.
Javascript).
I think this is the key to this whole discussion.
I doubt PHP will ever be able to fully support JavaScript- and
Lisp-style closures.
To take Stas' example to another level:
function foo()
{
$bar = function () { echo "bar"; }
return $bar;
}
$bar = foo();
$bar(); // does this work?
According to our current current syntax:
function foo()
{
$bar = create_function('', 'echo "bar";');
return $bar;
}
$bar = foo();
$bar(); // this does work
I don't know Lisp very well at all, but in JavaScript, functions are
general containers, and this sort of thing works fine, albeit VERY
differently. PHP's scoping rules are already completely different from
JavaScript's (there's no way to access the parent scope unless it
happens to be the global scope).
I strongly prefer Wez's syntax for anonymous function declaration. It
would help on many levels, from readability to syntax-highlighting, to
optimization (maybe...).
On optimization, the question becomes "how does Wez's proposal tokenize?"
--------Old:
T_OPEN_TAG
: <?php
T_VARIABLE
: $bar
T_WHITESPACE
:
=
T_WHITESPACE
:
T_STRING
: create_function
(
T_CONSTANT_ENCAPSED_STRING
: ''
,
T_WHITESPACE
:
T_CONSTANT_ENCAPSED_STRING
: 'echo "bar";'
)
;
--------New:
T_OPEN_TAG
: <?php
T_VARIABLE
: $bar
T_WHITESPACE
:
=
T_WHITESPACE
:
T_FUNCTION
: function
(
)
T_WHITESPACE
:
{
T_WHITESPACE
:
T_ECHO
: echo
T_WHITESPACE
:
T_CONSTANT_ENCAPSED_STRING
: "bar"
;
T_WHITESPACE
:
}
;
If the answer is "New", then this could be compiled at.. well,
compile-time, not at execute time. That could be even more interesting.
(sorry for the long post.. most of it's code (-; )
S
If the answer is "New", then this could be compiled at.. well,
compile-time, not at execute time. That could be even more interesting.
If it would create anonymous function compile-time, it would be a big
advantage to Wez's patch because then this function could be cached.
Thinking about this, maybe it is the reason enough to do this even if
it's not real closure.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
If it would create anonymous function compile-time, it would be a big
advantage to Wez's patch because then this function could be cached.
Thinking about this, maybe it is the reason enough to do this even if
it's not real closure.
On mulling this over a bit more, other than quick one-off callbacks
(which would definitely benefit from avoiding compile on every request),
one of the key reasons to use create_function()
is actually to create
dynamic functions:
$fancyVer = create_function('', 'return "PHP " . phpversion()
;');
// could be optimized as:
$fancyVer = create_function('', 'return "PHP ' . phpversion()
.'";');
(the latter only calls phpversion()
at declaration, not each time the
lambda runs)
Since phpversion()
is available globally, this isn't a problem. But what
happens if we want to use a variable, instead?
$ver = phpversion()
;
$fancyVer = create_function('', "return 'PHP $ver';");
// this currently works ^
How would this be rewritten, though?
$ver = phpversion()
;
$fancyVer = function () { return "PHP $ver"; };
where would $ver come from? the parent scope? the lambda's local scope?
what if it's defined in both places?
S
I've been thinking about this on and off today too.
Something along the lines of the following is more in the PHP spirit:
$ver = phpversion()
;
$fancyVer = function () { lexical $ver; return "PHP $ver"; };
Where "lexical" is a keyword that means "inherit this variable from
the current lexical scope". I'm not suggesting that this is a good
name for the keyword, it's just something that springs to mind.
So, given some way to explicitly reference the scope where the
function was "defined", what happens when you call $fancyVer after
that scope has gone away:
function doSomething() {
$ver = phpversion()
;
return function () { lexical $ver; return "PHP $ver"; };
}
$func = doSomething();
$func(); # the doSomething() scope (hash table) doesn't exist any more
This could perhaps be solved by taking a reference to $ver when the
function is bound, but I don't know enough about the ZE to understand
the implications of that; it would probably require a bit more state
tracking per zend_function so that we know that we need to do that
step during binding.
--Wez.
If it would create anonymous function compile-time, it would be a big
advantage to Wez's patch because then this function could be cached.
Thinking about this, maybe it is the reason enough to do this even if
it's not real closure.On mulling this over a bit more, other than quick one-off callbacks
(which would definitely benefit from avoiding compile on every
request),
one of the key reasons to usecreate_function()
is actually to create
dynamic functions:$fancyVer = create_function('', 'return "PHP " .
phpversion()
;');
// could be optimized as:
$fancyVer = create_function('', 'return "PHP ' .phpversion()
.'";');(the latter only calls
phpversion()
at declaration, not each time the
lambda runs)Since
phpversion()
is available globally, this isn't a problem. But
what
happens if we want to use a variable, instead?$ver =
phpversion()
;
$fancyVer = create_function('', "return 'PHP $ver';");
// this currently works ^How would this be rewritten, though?
$ver =phpversion()
;
$fancyVer = function () { return "PHP $ver"; };where would $ver come from? the parent scope? the lambda's local
scope?
what if it's defined in both places?S
If we can solve the scoping problem (perhaps via references as you
mentioned), then lexical (or another keyword, to be debated endlessly
for months, whose name-debate will delay the implementation of this
functionality, but I digress...) seems like a good solution to grabbing
scope, and fits the "PHP Way", IMO.
So, given some way to explicitly reference the scope where the function
was "defined", what happens when you call $fancyVer after that scope has
gone away:
This was my next question (-:
This could perhaps be solved by taking a reference to $ver when the
function is bound, but I don't know enough about the ZE to understand
the implications of that; it would probably require a bit more state
tracking per zend_function so that we know that we need to do that step
during binding.
JavaScript (and I suspect other Lisp-like languages) solves this by
making the function an actual closure—the defined function maintains
access to the parent scope, even after the parent's hash table (or
however it works in JS) would have normally been destroyed.
I think the key thing to remember here is that JS is fundamentally
different from PHP. Functions are objects in JS, and they always have
access to variables from all parent scopes. I don't think PHP can (or
should) ever implement this.
I also don't know what I'm talking about when it comes to ZE internals,
so if I'm way off base, feel free to put me in line (-:
(I maintain that JS' wonky (though useful) scoping rules should never be
assimilated in PHP.)
S
I've been thinking about this on and off today too.
Something along the lines of the following is more in the PHP spirit:$ver =
phpversion()
;
$fancyVer = function () { lexical $ver; return "PHP $ver"; };Where "lexical" is a keyword that means "inherit this variable from the
current lexical scope". I'm not suggesting that this is a good name for
the keyword, it's just something that springs to mind.
How this is going to work? Variables are not interpreted by the compiler
now...
So, given some way to explicitly reference the scope where the function
was "defined", what happens when you call $fancyVer after that scope has
gone away:
Exactly! That's why it is hard to do closures in PHP :)
This could perhaps be solved by taking a reference to $ver when the
function is bound, but I don't know enough about the ZE to understand
the implications of that; it would probably require a bit more state
$ver would not even exist when we compile it - $ver appears in run-time
and we want function to be created in compile-time!
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I've been thinking about this on and off today too.
Something along the lines of the following is more in the PHP spirit:$ver =
phpversion()
;
$fancyVer = function () { lexical $ver; return "PHP $ver"; };Where "lexical" is a keyword that means "inherit this variable from the
current lexical scope". I'm not suggesting that this is a good name for
the keyword, it's just something that springs to mind.How this is going to work? Variables are not interpreted by the compiler
now...So, given some way to explicitly reference the scope where the function
was "defined", what happens when you call $fancyVer after that scope has
gone away:Exactly! That's why it is hard to do closures in PHP :)
What about just having a function that allows retrieving variables from
the parent scope?
mixed seek_var( $name [, $levels=1, [ $startLevel=0 ] ] )
Returns the the value of the variable with name $name in the
current of parent lexical scopes. By default the seek will
only search for the variable in the current and immediate
parent scopes but this can be tailored to meet any particular
need including searching to the top by setting $levels to -1.
Additionally by setting $startLevel greater than 0, the
search can be confined to scopes outside of the current
lexical scope. If the request variable is not found then
`E_NOTICE` is generated and null is returned.
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
What about just having a function that allows retrieving variables from
the parent scope?mixed seek_var( $name [, $levels=1, [ $startLevel=0 ] ] )
How you are going to know where "parent scope" is? It can even be not
existing anymore, or can be separated by any number of parameter
passing. Remember that the function is defined at compile-time, but
invoked at run-time by some other function.
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
What about just having a function that allows retrieving variables from
the parent scope?mixed seek_var( $name [, $levels=1, [ $startLevel=0 ] ] )
How you are going to know where "parent scope" is? It can even be not
existing anymore, or can be separated by any number of parameter
passing. Remember that the function is defined at compile-time, but
invoked at run-time by some other function.
I guess I was primarily thinking in the context of the anonymous
function being defined in your previous example. As such the parent
scope is known (or at least can be expected), unless (unknown to me)
within the internal C code the scope can change other than the hierarchy
one would see visually while writing PHP code. From your example:
What happens if you do this:
$data = array("zoo", "orange", "car", "lemon", "apple");
$rev = 1;
usort($data, function($a, $b) { return $rev?strcmp($a, $b):!
strcmp($a,
$b); });
var_dump($data); # data is sorted alphabetically
We would have:
<?php
$data = array("zoo", "orange", "car", "lemon", "apple");
$rev = 1;
usort($data, function($a, $b) { return seek_var( 'rev' )?strcmp($a,
$b):!strcmp($a,
$b); });
var_dump($data); # data is sorted alphabetically
?>
Can we not expect that the lexical scope of the $rev is the immediate
parent of the anonymous function at runtime? Obviously this could also
work for normally defined functions if there's an expectation of the
calling environment having some specific variable defined.
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
I guess I was primarily thinking in the context of the anonymous
function being defined in your previous example. As such the parent
scope is known (or at least can be expected), unless (unknown to me)
It is known in compile-time. But functions are not called in
compile-time. And in run-time, inside usort()
- which could in other
case be some kind of foo_sort() passing its second parameter to a dozen
of other functions, one of which uses it to invoke comparator function -
you can not know where the scope in which usort was called is with
regard to the scope of the executing anonymous function. And if you took
this function name and saved it in the variable - it could be that the
scope it was defined in does not exist anymore.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I guess I was primarily thinking in the context of the anonymous
function being defined in your previous example. As such the parent
scope is known (or at least can be expected), unless (unknown to me)It is known in compile-time. But functions are not called in
compile-time. And in run-time, insideusort()
- which could in other
case be some kind of foo_sort() passing its second parameter to a dozen
of other functions, one of which uses it to invoke comparator function -
you can not know where the scope in which usort was called is with
regard to the scope of the executing anonymous function. And if you took
this function name and saved it in the variable - it could be that the
scope it was defined in does not exist anymore.
I'm not arguing the preservation of the exact value of $rev when the
anonymous function was created (as would be the case with a closure).
I'm thinking of the variable being whatever is defined in the parent
regardless. As in my proposal, the seek could search all the way up to
the top in which case the $rev would be found if it had been defined as
expected. At any rate, I guess this is diverging from the real
discussion of anonymous functions :)
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
regardless. As in my proposal, the seek could search all the way up to
the top in which case the $rev would be found if it had been defined as
The top of what? Anonymous function could be called from global scope too.
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
regardless. As in my proposal, the seek could search all the way up to
the top in which case the $rev would be found if it had been defined asThe top of what? Anonymous function could be called from global scope too.
Then it has 1 level to travel to the top since it's own scope isn't the
global scope.
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
We could compile the anonymous function at compile-time but leave
placeholders which need to be "fixed-up" when at run-time the actual
closure is created. For this purpose we could introduce a new magical
variables $_SCOPE["var"] which references the current $var during fixup
time.
So here's an example:
$var = php_version();
$fancyVer = function () { return "PHP $_SCOPE['ver']; };
So what this does is compile the "anonymous function" at compile-time,
but when this line is executed (note, this line of code should also be
reached during execution), then we do the fix-up for $_SCOPE variables.
Regular variables remain what they would in create_function()
. Fix-up
time would be faster than compiling the code.
Thoughts?
Andi
So what this does is compile the "anonymous function" at compile-time,
but when this line is executed (note, this line of code should also be
reached during execution), then we do the fix-up for $_SCOPE variables.
Yes, this is basically what Wez was proposing I guess. This would
require new hashtable for _SCOPE (and/or adding _SCOPE elements on
execution of anon-func line) in the function run-time data.
Thoughts?
This might work, still not sure if we really want that in PHP. On one
side, it's cool, on other side closures can develop into a very messy
code :)
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Stanislav Malyshev wrote:
Thoughts?
This might work, still not sure if we really want that in PHP. On one
side, it's cool, on other side closures can develop into a very messy
code :)
Yeah well .. for the single task of callbacks they are great and prevent
a lot of messiness .. I think its messy to pollute the namespace for
something which is not intended for reuse .. maybe we need to
artificially limit its uses just like for "goto".
regards,
Lukas
Why would this pollute less? It would still pollute the namespace.
-----Original Message-----
From: Lukas Kahwe Smith [mailto:mls@pooteeweet.org]
Sent: Monday, March 19, 2007 3:08 PM
To: Stas Malyshev
Cc: Andi Gutmans; Robert Cummings; Wez Furlong; Sean Coates;
internals@lists.php.net
Subject: Re: [PHP-DEV] PATCH: anonymous functions in PHPStanislav Malyshev wrote:
Thoughts?
This might work, still not sure if we really want that in
PHP. On one
side, it's cool, on other side closures can develop into a
very messy
code :)Yeah well .. for the single task of callbacks they are great
and prevent a lot of messiness .. I think its messy to
pollute the namespace for something which is not intended for
reuse .. maybe we need to artificially limit its uses just
like for "goto".regards,
Lukas
I've been thinking about this in the car, and it won't quite work as-is.
Here's a contrived example:
$funcs = array();
for ($i = 0; $i < 10; $i++) {
$funcs[] = function() { return $_SCOPE['i']; };
}
Here I'm assuming that $_SCOPE takes a copy of $i during fixup.
The problem here is that the function is compiled once, so there is
only one place to stash the fixup info for $_SCOPE, which leaves the
results of calling any of the functions in $funcs undefined. (Just
in case it's not clear, the intention is to create 10 anonymous
functions, which return values 0 through 9).
There are two ways to solve this, both give the same visible result
to the person writing the code, but one is more invasive.
The first solution is to have a unique function name generated on
each run through the loop. The function name would be an alias (ala
FALIAS) to the opcodes, so that there would only be one version of
the compiled opcodes. The based on the information from $_SCOPE,
copies of the variables from the instantiating scope would be stored
along with the oparray, keyed by the unique function name.
When the function is called, the name being invoked is used to locate
the saved variables, which are then used to pre-populate the local
scope for the function. $_SCOPE['i'] would have been transposed to
simply $i in the op_array.
So, in psuedo code the above would generate a funcs array like:
$funcs[0] = "__anon_0";
$funcs[1] = "__anon_1";
and when the engine goes to invoke __anon_0:
function __anon_0() {
$_LOCALS = get_scope_vars_for('__anon_0');
return $i;
}
Where the $_LOCALS line represents the prologue in the ZE that sets
up the local scope for that function "frame".
The second possibility would be to make a first-class callable zval
type which stores that information in the return value from the
function declaration. The callable type would store a pointer to the
op_array as well as a hash table to use to initialize the local scope
of the function. Again, this would be created based on the $_SCOPES
fixup information, and again, $_SCOPES['i'] would be rewritten as
simply $i in the op_array.
So the funcs array might look like this is var_dump()
'd:
0 => callable('__anon_0', array('i' => 0)),
1 => callable('__anon_0', array('i' => 1)),
2 => callable('__anon_0', array('i' => 2))
Adding a type seems cleaner, but obviously requires more work as the
rest of the internals need to understand what to do with it.
A third possibility is similar to the second, but a bit less
invasive. Create a callable class type to encapsulate that
information. The rest of the internals would see $funcs[0] as an
object, but the engine would know that calling it will invoke the
appropriate function, prepping the local scope as described above.
--Wez.
We could compile the anonymous function at compile-time but leave
placeholders which need to be "fixed-up" when at run-time the actual
closure is created. For this purpose we could introduce a new magical
variables $_SCOPE["var"] which references the current $var during
fixup
time.
So here's an example:$var = php_version();
$fancyVer = function () { return "PHP $_SCOPE['ver']; };So what this does is compile the "anonymous function" at compile-time,
but when this line is executed (note, this line of code should also be
reached during execution), then we do the fix-up for $_SCOPE
variables.
Regular variables remain what they would increate_function()
. Fix-up
time would be faster than compiling the code.Thoughts?
Andi
Hi Wez,
There are various ways to go about implementing this. While reading your
email I've had another couple of ideas incl. some funky parameter
passing games. All these ideas are legit and have pros/cons but what's
most important is actually from a feature point of view, whether we want
to do something, and if so what.
So I think the questions are:
a) Do we want to support another way to create anonymous functions ala
create_function, even if it doesn't allow binding to values (closures)
from the outer scope (which create_function()
supports doing by value;
by embedding variables in the string).
b) If the answer is yes, then do we want to have a syntax (ala
$_SCOPE["i"] or similar)? If so, what does it do? Does it bind to outer
variables or does it "embed" the values. If the latter, do we care more
about the actual functionality or performance.
I hope these questions are clear. I think we need to be very careful
when going down this route because some have already alluded that it
might be confusing and not quite the PHP spirit, on the other hand there
are also valid reasons for doing it. In any case, if we go down this
route we should be crystal clear in what behavior we expect and need to
feel comfortable that it doesn't have a high wtf-factor associated with
it.
I need to sleep on it and think about it a bit more tomorrow.
Thoughts?
Andi
-----Original Message-----
From: Wez Furlong [mailto:wez@omniti.com]
Sent: Monday, March 19, 2007 5:03 PM
To: Andi Gutmans
Cc: Stas Malyshev; Robert Cummings; Sean Coates;
internals@lists.php.net
Subject: Re: [PHP-DEV] PATCH: anonymous functions in PHPI've been thinking about this in the car, and it won't quite
work as-is.
Here's a contrived example:$funcs = array();
for ($i = 0; $i < 10; $i++) {
$funcs[] = function() { return $_SCOPE['i']; }; }Here I'm assuming that $_SCOPE takes a copy of $i during fixup.
The problem here is that the function is compiled once, so
there is only one place to stash the fixup info for $_SCOPE,
which leaves the results of calling any of the functions in
$funcs undefined. (Just in case it's not clear, the
intention is to create 10 anonymous functions, which return
values 0 through 9).There are two ways to solve this, both give the same visible
result to the person writing the code, but one is more invasive.The first solution is to have a unique function name
generated on each run through the loop. The function name
would be an alias (ala
FALIAS) to the opcodes, so that there would only be one
version of the compiled opcodes. The based on the
information from $_SCOPE, copies of the variables from the
instantiating scope would be stored along with the oparray,
keyed by the unique function name.When the function is called, the name being invoked is used
to locate the saved variables, which are then used to
pre-populate the local scope for the function. $_SCOPE['i']
would have been transposed to simply $i in the op_array.So, in psuedo code the above would generate a funcs array like:
$funcs[0] = "__anon_0";
$funcs[1] = "__anon_1";and when the engine goes to invoke __anon_0:
function __anon_0() {
$_LOCALS = get_scope_vars_for('__anon_0');
return $i;
}Where the $_LOCALS line represents the prologue in the ZE
that sets up the local scope for that function "frame".The second possibility would be to make a first-class
callable zval type which stores that information in the
return value from the function declaration. The callable
type would store a pointer to the op_array as well as a hash
table to use to initialize the local scope of the function.
Again, this would be created based on the $_SCOPES fixup
information, and again, $_SCOPES['i'] would be rewritten as
simply $i in the op_array.So the funcs array might look like this is
var_dump()
'd:0 => callable('__anon_0', array('i' => 0)),
1 => callable('__anon_0', array('i' => 1)),
2 => callable('__anon_0', array('i' => 2))Adding a type seems cleaner, but obviously requires more work
as the rest of the internals need to understand what to do with it.A third possibility is similar to the second, but a bit less
invasive. Create a callable class type to encapsulate that
information. The rest of the internals would see $funcs[0]
as an object, but the engine would know that calling it will
invoke the appropriate function, prepping the local scope as
described above.--Wez.
We could compile the anonymous function at compile-time but leave
placeholders which need to be "fixed-up" when at run-time
the actual
closure is created. For this purpose we could introduce a
new magical
variables $_SCOPE["var"] which references the current $var during
fixup time.
So here's an example:$var = php_version();
$fancyVer = function () { return "PHP $_SCOPE['ver']; };So what this does is compile the "anonymous function" at
compile-time,
but when this line is executed (note, this line of code
should also be
reached during execution), then we do the fix-up for $_SCOPE
variables.
Regular variables remain what they would in
create_function()
. Fix-up
time would be faster than compiling the code.Thoughts?
Andi
thanks to the demo script that bring us to this topic again. i must
agree that designing a language isn't as simple as most ppl might
think. so thank u if u keep thinking this topic.
i would remind that the static variable make it not cache friendly, so
i suggest the anonymous-name should be something like the temp late
binding class name. just keep cache-friendly in mind, thanks
There are various ways to go about implementing this. While reading
your
email I've had another couple of ideas incl. some funky parameter
passing games. All these ideas are legit and have pros/cons but what's
most important is actually from a feature point of view, whether we
want
to do something, and if so what.
So I think the questions are:
a) Do we want to support another way to create anonymous functions ala
create_function, even if it doesn't allow binding to values (closures)
from the outer scope (whichcreate_function()
supports doing by value;
by embedding variables in the string).
b) If the answer is yes, then do we want to have a syntax (ala
$_SCOPE["i"] or similar)? If so, what does it do? Does it bind to
outer
variables or does it "embed" the values. If the latter, do we care
more
about the actual functionality or performance.I hope these questions are clear. I think we need to be very careful
when going down this route because some have already alluded that it
might be confusing and not quite the PHP spirit, on the other hand
there
are also valid reasons for doing it. In any case, if we go down this
route we should be crystal clear in what behavior we expect and need
to
feel comfortable that it doesn't have a high wtf-factor associated
with
it.I need to sleep on it and think about it a bit more tomorrow.
Thoughts?
I think any kind of anonymous function is going to have somewhat of a
wtf factor.
Adding in the full-blown closure and scoping definitions is
geometrically more wtf factor.
I realize that it's a really cool thing, and fun to mess with, and the
CS Major / AI Researcher in me is screaming "go for it"...
But the pragmatic PHP user and mailing-list-answer-guy inside me is
saying "Hell no" :-)
After a night's sleep...
I think solving the common need for 99% of the people with a nice
simple clean anonymous function is PHP way.
Adding the complexity of closures and scoping rules is, imho, not the
PHP way because it's just so esoteric and complex.
If somebody has a real-life demonstrated NEED for the
closures/scoping, by all means, bring it up.
But, so far, it seems like it's been more "wow, this would be really
geeky cool!"...
There's nothing wrong with being geeky cool, but it's not something
that should be thrown into all day every day workhorse of PHP core,
imho.
Of course, I've also figured out that maybe the reason that all this
came up is that it's dead easy to write it with a full-blown
closure/scope system, even if it's not real clear what the actual
rules are, than it is to restrict it to dis-allow that...
I dunno what to say to that, other than to, perhaps, leave the simple
implementation there, and document the use of out-of-scope variables
as "undefined"...
Though that will probably end up with a bunch of scripters using
out-of-scope vars with no clue what they just did and how morally
wrong it was to use an intentionally undocumented feature.
But if that's the best that can be done with the resources available,
I think it would be a good compromise.
Especially as it leaves open the possiblity of someday nailing down a
complete clear definition of what the scoping rules turn out to be,
with room for experimentation in the meantime without violating BC.
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
Though that will probably end up with a bunch of scripters using
out-of-scope vars with no clue what they just did and how morally
wrong it was to use an intentionally undocumented feature.
Without the right tool, the data needs will be punted to $GLOBALS.
Please tell me you're not advocating $GLOBALS in favour of a clean and
concise closure :)
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
So does this mean that the patch would be included even in its somewhat broken
state? Just don't allow it in loops or warn when it is or access to outside
scope variables.
I need to get VLD working on Windows to see what the fuss is all about. I
thought everything is compiled to oplines, if that is so, then why not back up
to the previous function space, keep the scope when you encounter an inside
function, which should be assumed to be a closure.
If you compile and store the closure function in top level userspace, then it
should be able to be accessed at runtime.
function test()
{
$f = function () { return 0; }
return $f;
}
$closure = test();
$closure();
Err, Pseudo-oplines, but since I don't exactly know anything about PHP opcodes,
I'm just pulling this stuff out of my ass.
CREATE_FUNCTION test
CREATE_FUNCTION zend_anon_0
RET_VAL 0
END_FUNCTION
END_FUNCTION
CALL 'test'
ASSIGN $0, $valuefunction
(I have to admit that I'm not that far in Assembler for procedures (yes, I'm a
kook, but I can change baby, just give me another chance) and I apologize, but
thanks for reading this far!)
CALL $0
In which at run time the following can be replaced with:
CREATE_FUNCTION 'zend_anon_0'
RET_VAL 0
END_FUNCTION
CREATE_FUNCTION 'test'
RET_CLOSURE 'zend_anon_0'
END_FUNCTION
CALL 'test'
CALL 'zend_anon_0'
I do recall that parameters are passed somewhere. Eh. Aside from getting the
Oplines, opcodes, as well as the instruction names wrong, and pretty much
everything. What else is wrong with this?
But if that's the best that can be done with the resources available,
I think it would be a good compromise.Especially as it leaves open the possiblity of someday nailing down a
complete clear definition of what the scoping rules turn out to be,
with room for experimentation in the meantime without violating BC.
Err, Pseudo-oplines, but since I don't exactly know anything about PHP
opcodes, I'm just pulling this stuff out of my ass.CREATE_FUNCTION test
CREATE_FUNCTION zend_anon_0
RET_VAL 0
END_FUNCTION
END_FUNCTION
CALL 'test'
ASSIGN $0, $valuefunction
It looks like you misunderstand how the engine compiles functions. Each
function has its own op array. Also, the code you brought is less
interesting. More interesting is code such as:
function prefixer($p)
{
$f = function ($name) { return "$p. $name"; }
return $f;
}
$mr = prefixer("Mr");
$mrs = prefixer("Mrs");
echo $mr("Jones");
echo $mrs("Jones");
As you could have guessed, that should result in "Mr. Jones" and "Mrs.
Jones" printed. Figuring out where the "Mr." comes from when
$mr("Jones") is called would help understand how closure works.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Hi,
I think solving the common need for 99% of the people with a nice
simple clean anonymous function is PHP way.
Right. But then those people add 2 + 2 and get frustrated because they
can't do the obvious ;)
If somebody has a real-life demonstrated NEED for the
closures/scoping, by all means, bring it up.
Plain old google brought up:
http://groovy.codehaus.org/Martin+Fowler's+closure+examples+in+Groovy
among other hits (Groovy syntax should be easy enough to follow).
Regards,
Michael
Michael Walter wrote:
Right. But then those people add 2 + 2 and get frustrated because they
can't do the obvious ;)
I find it all but obvious to being able to use non-local, non-global
variables in PHP. It's one of the main PHP points IMHO that a variables
is either local or explicitely accessed through $_GLOBALS (or super
globals). It gives me a warm and fuzzy feeling that I know everything
else is undefined and won't clash.
If somebody has a real-life demonstrated NEED for the
closures/scoping, by all means, bring it up.Plain old google brought up:
http://groovy.codehaus.org/Martin+Fowler's+closure+examples+in+Groovy
among other hits (Groovy syntax should be easy enough to follow).
He said real-life examples (-:C
- Chris
Hi,
Michael Walter wrote:
Right. But then those people add 2 + 2 and get frustrated because they
can't do the obvious ;)I find it all but obvious to being able to use non-local, non-global
variables in PHP. It's one of the main PHP points IMHO that a variables
is either local or explicitely accessed through $_GLOBALS (or super
globals). It gives me a warm and fuzzy feeling that I know everything
else is undefined and won't clash.
Which seems to fit Andi's $_SCOPE proposal.
If somebody has a real-life demonstrated NEED for the
closures/scoping, by all means, bring it up.Plain old google brought up:
http://groovy.codehaus.org/Martin+Fowler's+closure+examples+in+Groovy
among other hits (Groovy syntax should be easy enough to follow).He said real-life examples (-:C
Is that like "enterprise" examples? ;)
Regards,
Michael
Michael Walter wrote:
I find it all but obvious to being able to use non-local, non-global
variables in PHP. It's one of the main PHP points IMHO that a variables
is either local or explicitely accessed through $_GLOBALS (or super
globals). It gives me a warm and fuzzy feeling that I know everything
else is undefined and won't clash.Which seems to fit Andi's $_SCOPE proposal.
Yes, but is a point against a real closure proposal.
He said real-life examples (-:C
Is that like "enterprise" examples? ;)
No, it's like non-textbook example (which can also run on a Bird of Prey
or a Klingon starship :-))
- Chris
Michael Walter wrote:
Which seems to fit Andi's $_SCOPE proposal.
Yes, but is a point against a real closure proposal.
I think the defining property of a "real" closure proposal is having
the lexical scope available.
So I guess we both agree on that something like $_SCOPE would be a
useful thing to have.
He said real-life examples (-:C
Is that like "enterprise" examples? ;)
No, it's like non-textbook example (which can also run on a Bird of Prey
or a Klingon starship :-))
Closures become really useful when you start building abstractions on
top of anonymous functions, since in the process of abstraction you
often replace literals/constants by parameters (similar to how
function parameters become useful when you start refactoring common
code into functions ;).
A simple real-life example is:
function pick($member)
{
return create_function('$x', 'return $x->'.$member.';');
}
which could be used e.g. in
array_map(pick('age'), $people).
Arguably, in this case you could as well write:
array_map(function($p) {return $p->age;}, $people);
but I believe it is easy to see how the problem generalizes.
Regards,
Michael
Michael Walter wrote:
A simple real-life example is:
function pick($member)
{
return create_function('$x', 'return $x->'.$member.';');
}which could be used e.g. in
array_map(pick('age'), $people).
Arguably, in this case you could as well write:
array_map(function($p) {return $p->age;}, $people);
but I believe it is easy to see how the problem generalizes.
Funnily enough you already show how this can currently be done.
My point would be to make simple things simple and keep complicated
things possible. As it is right now.
So I'd use
array_map(function($p) {return $p->age;}, $people);
or
usort($a, function($a, $b) { return strcmp($a->lastname, $b->lastname); });
to do Stefan Walk's example.
But something like your pick function using create_function if I
really wanted something more fancy.
- Chris
If somebody has a real-life demonstrated NEED for the
closures/scoping, by all means, bring it up.Plain old google brought up:
http://groovy.codehaus.org/Martin+Fowler's+closure+examples+in+Groovy
among other hits (Groovy syntax should be easy enough to follow).He said real-life examples (-:C
- Chris
function sort_by_key($key) {
return function($a, $b) {
if ($a[$key] < $b[$key])
return -1;
if ($a[$key] == $b[$key])
return 0;
return 1;
}
}
$a = array(
array('id' => 0, 'first_name' => 'john', 'last_name' => 'connor'),
...
);
usort($a, sort_by_key('last_name'));
function sort_by_key($key) {
For the record, I do like this syntax, but it COULD be rewritten using
current practices (see below).
class SortByKey {
public $key;
public function __construct($key) {
$this->key = $key;
}
public function do($a, $b) {
if ($a[$this->key] < $b[$this->key])
return -1;
if ($a[$this->key] == $b[$this->key])
return 0;
return 1;
}
}
$a = array(
array('id' => 0, 'first_name' => 'john', 'last_name' => 'connor'),
...
);
$Sorter = new SortByKey('last_name');
usort($a, array($Sorter, 'do'));
That said, I like the idea of a first class callable object.
For the example above, doing this:
class SortByKey implements Callable {
...
$Sorter();
Would actually execute $Sorter->do(); (obviously there's a problem when
$Sorter has a __toString (dynamic function call), but this seems to
nicely wrap all but the most basic case of callback, where an object
might be overkill.
Perhaps this could be implemented in SPL? (Just wondering if it's
possible at this point, I'm not campaigning for it..)
S
That said, I like the idea of a first class callable object.
For the example above, doing this:class SortByKey implements Callable {}
Note that this is what Java did since day one (it was thought that
anonymous inner classes were good enough). I heard that nowadays
people seem to think differently; apparently there are multiple
closure proposals for JDK 7.
Regards,
Michael
function sort_by_key($key) {
For the record, I do like this syntax, but it COULD be rewritten using
current practices (see below).
I know, and it can be done without typing so much:
class SortByKey {
function __call($name, $a) {
if ($a[0][$name] < $a[1][$name])
return -1;
if ($a[0][$name] == $a[1][$name])
return 0;
return 1;
}
}
$a = array(
array("a" => 1, "b" => 2),
array("a" => 2, "b" => 1),
);
usort($a, array(new SortByKey, "b"));
That doesn't change the fact that it's a hack ;)
Regards,
Stefan
For the record, I do like this syntax, but it COULD be rewritten using
current practices (see below).
That's a good point - actually most uses of closures could be with some
effort rewritten as classes. The difference would be that in case of
closures, closure chooses which parts of context to import, and in case
of objects you would need to explicitly supply the parameters. Also,
you'd have to explicitly call the object methods, can't just do $foo().
And of course it's not as slick and generic as closure - you'd have to
write new class for each case.
class SortByKey implements Callable {
...
$Sorter();
Well, you can do it now by using call_user_func()
, and you also have
advantage of using more than one function per class :) So I'm not sure
it's necessary.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Plain old google brought up:
http://groovy.codehaus.org/Martin+Fowler's+closure+examples+in+Groovy
among other hits (Groovy syntax should be easy enough to follow).He said real-life examples (-:C
I said real-life NEED, as in, "I can't do X in a clean/decent way
without a closure"
Wanting to write obfuscated natural-language-looking code is not a NEED.
:-) :-) :-)
The only programmers I ever met in 25 years who NEEDED closures were
AI Researchers (and I was one). And, yes, there IS a need for them in
that kind of work.
How many AI researchers have turned to PHP as their language of choice?
0.5, counting the guy who wrote that neural network thingie in PHP as
his idea of a Good Time is all I know of...
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some indie artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
I've been wanting a true first-class callable type for a while.
-Andrei
The second possibility would be to make a first-class callable zval
type which stores that information in the return value from the
function declaration. The callable type would store a pointer to the
op_array as well as a hash table to use to initialize the local scope
of the function. Again, this would be created based on the $_SCOPES
fixup information, and again, $_SCOPES['i'] would be rewritten as
simply $i in the op_array.So the funcs array might look like this is
var_dump()
'd:0 => callable('__anon_0', array('i' => 0)),
1 => callable('__anon_0', array('i' => 1)),
2 => callable('__anon_0', array('i' => 2))Adding a type seems cleaner, but obviously requires more work as the
rest of the internals need to understand what to do with it.A third possibility is similar to the second, but a bit less invasive.
Create a callable class type to encapsulate that information. The
rest of the internals would see $funcs[0] as an object, but the engine
would know that calling it will invoke the appropriate function,
prepping the local scope as described above.--Wez.
of the function. Again, this would be created based on the $_SCOPES
fixup information, and again, $_SCOPES['i'] would be rewritten as
simply $i in the op_array.So the funcs array might look like this is
var_dump()
'd:0 => callable('__anon_0', array('i' => 0)),
1 => callable('__anon_0', array('i' => 1)),
2 => callable('__anon_0', array('i' => 2))
How do you know it's 'i'? Does it mean compiler should record any
reference to _SCOPES? What if I do $_SCOPES[$foo] - is it that
unthinkable? What if I doo $a = "_SCOPES", $$a[$foo]?
Only way I see you can really do it is to explicitly declare the
imported variables, otherwise you'll lose them - PHP is too dynamic for
compiler to be able to statically resolve it.
On a side note: why one needs callable type? What can be done with it
which can't be done with string and $string()?
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
What if I doo $a = "_SCOPES", $$a[$foo]?
FWIW, this doesn't work with the other superglobals (in function context):
sean@sarcasm:~$ php -r '$_GET["foo"] = "bar"; function baz() { $get =
"_GET"; return ${$get}["foo"]; } $get = "_GET"; echo ${$get}["foo"],
baz(), "\n";'
bar
Notice: Undefined variable: _GET in Command line code on line 1
(this is documented)
S
FWIW, this doesn't work with the other superglobals (in function context):
sean@sarcasm:~$ php -r '$_GET["foo"] = "bar"; function baz() { $get =
"_GET"; return ${$get}["foo"]; } $get = "_GET"; echo ${$get}["foo"],
baz(), "\n";'
bar
Notice: Undefined variable: _GET in Command line code on line 1(this is documented)
Ouch... ok. But $_SCOPES[$foo] should work, shouldn't it?
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Stanislav Malyshev wrote:
FWIW, this doesn't work with the other superglobals (in function
context):
sean@sarcasm:~$ php -r '$_GET["foo"] = "bar"; function baz() { $get =
"_GET"; return ${$get}["foo"]; } $get = "_GET"; echo ${$get}["foo"],
baz(), "\n";'
bar
Notice: Undefined variable: _GET in Command line code on line 1(this is documented)
Ouch... ok. But $_SCOPES[$foo] should work, shouldn't it?
$_SCOPE doesn't need to be that special... It can just be an object with
overloaded array access... Whenever a dim is fetched for that object,
check current_execute_data->prev->symbol_table for the variable and
return that.
-Sara
$_SCOPE doesn't need to be that special... It can just be an object with
overloaded array access... Whenever a dim is fetched for that object,
check current_execute_data->prev->symbol_table for the variable and
return that.
Once again - current_execute_data->prev at closure runtime has nothing
common with the symbol table that closure is supposed to capture. The
symbol table is present at the closure instantiation time - i.e. when
$foo = function(...) {...} (1)
is executed, not when
$foo(...) (2)
is executed. (1) may be executed in scope entirely unrelated to (2) and
only in rare special cases scope (1) would precede scope (2). In many
other cases, totally unrelated scope would be predecessor of (2) and
getting values from there would be a big surprise to the user.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Stanislav Malyshev wrote:
$_SCOPE doesn't need to be that special... It can just be an object
with overloaded array access... Whenever a dim is fetched for that
object, check current_execute_data->prev->symbol_table for the
variable and return that.Once again - current_execute_data->prev at closure runtime has nothing
common with the symbol table that closure is supposed to capture. The
symbol table is present at the closure instantiation time - i.e. when
$foo = function(...) {...} (1)
is executed, not when
$foo(...) (2)
is executed. (1) may be executed in scope entirely unrelated to (2) and
only in rare special cases scope (1) would precede scope (2). In many
other cases, totally unrelated scope would be predecessor of (2) and
getting values from there would be a big surprise to the user.
Ah, I understand now. This isn't something which should be evaluated
when the function is run, but rather when it's bound.
No sir, I don't like it. -1 from me.
-Sara
You need the callable type to store the closure information.
Either that, or you need to store it in the op_array, which is "bad"
because you don't know when you can free that closure state, so you
have to carry it around for the rest of the request.
I agree about $_SCOPES['foo']. I'm actually starting to lean towards
just copying the entire local scope hash table and storing it in the
callable/closure, and using that to initialize the symtable when you
call into the function.
--Wez.
of the function. Again, this would be created based on the
$_SCOPES fixup information, and again, $_SCOPES['i'] would be
rewritten as simply $i in the op_array.So the funcs array might look like this is
var_dump()
'd:0 => callable('__anon_0', array('i' => 0)),
1 => callable('__anon_0', array('i' => 1)),
2 => callable('__anon_0', array('i' => 2))How do you know it's 'i'? Does it mean compiler should record any
reference to _SCOPES? What if I do $_SCOPES[$foo] - is it that
unthinkable? What if I doo $a = "_SCOPES", $$a[$foo]?Only way I see you can really do it is to explicitly declare the
imported variables, otherwise you'll lose them - PHP is too dynamic
for compiler to be able to statically resolve it.On a side note: why one needs callable type? What can be done with
it which can't be done with string and $string()?Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Either that, or you need to store it in the op_array, which is "bad"
because you don't know when you can free that closure state, so you have
to carry it around for the rest of the request.
Well, this is a strong argument indeed. However adding new zval type is
a big step which adds complexity to the language and tools. We'd also
have to modify a bunch of places where callbacks are used to allow this.
I think though there's a middle way - if we modify callback type so that
instead of array($object, $name) it would accept array($object, $name,
$arguments) where arguments are the captured closure variables it might
be more convenient. The advantage is that if we don't have closure
variables, we don't need to do a thing. We'd need also to deal with
decision if we create closure in a class context would it belong to
class or global space.
I agree about $_SCOPES['foo']. I'm actually starting to lean towards
just copying the entire local scope hash table and storing it in the
callable/closure, and using that to initialize the symtable when you
call into the function.
That might be not that good an idea. Local table can be very large (and
what if it's global scope?), include all kinds of things you won't ever
need (such as resources used locally) and the user regards it as
transient and doesn't necessarily want to capture it into closure. Even
worse, non-closure anon function - i.e. not wanting to use any of the
parent context - would then still have the penalty of carrying all the
stuff around. I think explicitly declaring might be the best way...
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I'm not arguing the preservation of the exact value of $rev when the
anonymous function was created (as would be the case with a closure).
I'm thinking of the variable being whatever is defined in the parent
regardless. As in my proposal, the seek could search all the way up to
the top in which case the $rev would be found if it had been defined as
expected. At any rate, I guess this is diverging from the real
discussion of anonymous functions :)
If you've ever tried to hack on the source to anything that you didn't
write that also uses globals throughout (Gallery2, for example), you
know how hard it is to track down a single layer of scope that can be
defined [somewhere else].
Tracking this up the chain like a bubbled exception sounds like a
nightmare for debugging/comprehension, and IMO it's too magical.
One layer of scope might be useful: $_PARENT ?
More than that, and my head starts to hurt.
S
I'm not arguing the preservation of the exact value of $rev when the
anonymous function was created (as would be the case with a closure).
I'm thinking of the variable being whatever is defined in the parent
regardless. As in my proposal, the seek could search all the way up to
the top in which case the $rev would be found if it had been defined as
expected. At any rate, I guess this is diverging from the real
discussion of anonymous functions :)If you've ever tried to hack on the source to anything that you didn't
write that also uses globals throughout (Gallery2, for example), you
know how hard it is to track down a single layer of scope that can be
defined [somewhere else].Tracking this up the chain like a bubbled exception sounds like a
nightmare for debugging/comprehension, and IMO it's too magical.One layer of scope might be useful: $_PARENT ?
More than that, and my head starts to hurt.
Well I did originally suggest defaulting to the parent scope with
options for advanced users to climb higher :) Just because there are
unwashed masses as Richard Lynch likes to call it, doesn't mean we all
need to suffer their limitations.
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
How this is going to work? Variables are not interpreted by the
compiler now...
Well, the compiler would make a list of variables names to import and
store those in the zend_function structure. Then at the time the
function is bound (in response to a DECLARE_FUNCTION opcode), the
variable reference could be fixed up in the "same" way that global is
handled.
--Wez.
Well, the compiler would make a list of variables names to import and
store those in the zend_function structure. Then at the time the
function is bound (in response to a DECLARE_FUNCTION opcode), the
variable reference could be fixed up in the "same" way that global is
handled.
Global is not handled this way. Global creates reference at runtime
(i.e. when function is executed) to runtime variable in global space.
However, binding to compile scope can't work as globals do - since
binding should happen at "definition run-time" - e.g., when the function
definition is used. Adding binding capabilities to DECLARE_FUNCTION
might work though, but it is not clear what to do in case this is
declared in a loop (then it can't really be done compile-time unless we
clone this function each time). It must be also considered how these
values are added to the function symbol table when the function runs -
e.g. are they references or copies?
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
I've been thinking about this on and off today too.
Something along the lines of the following is more in the PHP spirit:$ver =
phpversion()
;
$fancyVer = function () { lexical $ver; return "PHP $ver"; };Where "lexical" is a keyword that means "inherit this variable from
the current lexical scope". I'm not suggesting that this is a good
name for the keyword, it's just something that springs to mind.
I believe "Environment" is what it was called back in CLOS when we
schlepped it around as an extra extra argument to functions that
needed data from outside function scope...
So, given some way to explicitly reference the scope where the
function was "defined", what happens when you call $fancyVer after
that scope has gone away:function doSomething() {
$ver =phpversion()
;
return function () { lexical $ver; return "PHP $ver"; };
}
$func = doSomething();
$func(); # the doSomething() scope (hash table) doesn't exist any moreThis could perhaps be solved by taking a reference to $ver when the
function is bound, but I don't know enough about the ZE to understand
the implications of that; it would probably require a bit more state
tracking per zend_function so that we know that we need to do that
step during binding.
This gets incredibly complex not only to figure out what to do in the
PHP source, but for scripters to figure out what the heck it does...
If it's making YOUR head spin, what will it do to the poor unwashed
masses?...
Obviously, an anonymous function is going to be inherently complex --
but keep it as simple as it can be.
I suspect that you could get away with JUST using global and/or static
as they exist now, not introduce yet another scoping keyword, and
anything that NEEDS to be done with an anonymous function can be
done.
Does anybody really NEED a variable whose scope is non-global and
captured at the time of the func definition, carried over beyond the
scope of that until it's executed?...
Somehow I think you're just complicating it "because you can" rather
than because anybody really NEEDS this.
You have to have a pretty esoteric function to need that kind of scope
control, no?
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
This gets incredibly complex not only to figure out what to do in the
PHP source, but for scripters to figure out what the heck it does...
Welcome to the world of closures :) But in most cases people use it to
do pretty basic stuff (unless they are CS majors with too much time on
their hands ;) - like creating "dynamic anonymous functions" - basically
resulting in the same as what create_function does, and some currying -
which, for those who doesn't know it, is technique of partially
instantiating a multi-argument function - i.e. making something like:
$addtwo = function ($a) { return $a+2; }
$six = $addtwo(4);
or more frequently something like this:
$var = "foo";
$compare_to_var = function($s) { return (str_compare($var, $s)<0); }
$strings_less_than_var = array_filter($array, $compare_to_var);
which is really powerful technique for dynamic language, though can
easily lead one to lose all track of what is happening if overused. For
more confusion see http://en.wikipedia.org/wiki/Currying :)
If it's making YOUR head spin, what will it do to the poor unwashed
masses?...
Unwashed masses better not do it :) Actually many "washed" masses have
hard time to understand these things too.
I suspect that you could get away with JUST using global and/or static
as they exist now, not introduce yet another scoping keyword, and
anything that NEEDS to be done with an anonymous function can be
done.
I guess this depends on definition of "NEEDS".
You have to have a pretty esoteric function to need that kind of scope
control, no?
Depends on your background. Some people consider LISP intuitive language
:) And if you work with Javascript, you probably would be doing it daily
- most AJAX toolkits rely on heavy usage of anonymous functions. Not
sure it needs to be in PHP though. It might be cool thing, but it's
definitely becomes very confusing very fast.
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
You have to have a pretty esoteric function to need that kind of
scope
control, no?Depends on your background. Some people consider LISP intuitive
language
:) And if you work with Javascript, you probably would be doing it
daily
- most AJAX toolkits rely on heavy usage of anonymous functions. Not
sure it needs to be in PHP though. It might be cool thing, but it's
definitely becomes very confusing very fast.
I almost finished my MS in CS with Artificial Intelligence
concentration at DePaul, so I was one of those CS students with too
much time on my hands.
Then I worked at an AI think tank lab at Northwestern University for
most of a decade using Lisp.
I gotta say that while it was Really Nifty to know all about those
esoteric closures, curries, and whatnot I have since forgot, mostly, I
didn't need these things on a daily basis even at that job.
So, yes, somebody somewhere "needs" this, but is it the kind of thing
that belongs in PHP?
I think not.
By "this" I mean the ability to have the lexical closure carry its
scope around with itself.
I WANT to have a simple clean anonymous function syntax.
Can't you just take the body of "create_function" with the syntax of
the patch, and marry those two?
How does the current create_function handle this same scope issue?
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
Can't you just take the body of "create_function" with the syntax of
the patch, and marry those two?
Well, that'd be a bit hard since the whole difference is that
create_function is runtime (thus having access to run-time values) while
anon-func we are trying to do here is compile-time (at least it makes a
lot of sense to do it compile-time). We could of course just leave the
scope thing alone and say "want access to other scope? tough luck, use
create_function/eval or globals".
How does the current create_function handle this same scope issue?
It doesn't AFAIK :) Since it's a close relative of eval, it can import
values of variables by inserting ones into function string, but nothing
more (i.e. you couldn't put an object there, and couldn't refer to a
variable - only insert it's value).
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Can't you just take the body of "create_function" with the syntax of
the patch, and marry those two?Well, that'd be a bit hard since the whole difference is that
create_function is runtime (thus having access to run-time values)
while
anon-func we are trying to do here is compile-time (at least it makes
a
lot of sense to do it compile-time). We could of course just leave the
scope thing alone and say "want access to other scope? tough luck, use
create_function/eval or globals".
I thought the original driving purpose was to not have the gnarly
quoting mess of create_function.
Yes, in the implementation, it turned out to be a compile-time closure.
Does that mean we really WANT to go there, just because it falls out
easily, or does that mean we should step back and look at the original
goal and see if maybe we've gone off-track?
How does the current create_function handle this same scope issue?
It doesn't AFAIK :) Since it's a close relative of eval, it can import
values of variables by inserting ones into function string, but
nothing
more (i.e. you couldn't put an object there, and couldn't refer to a
variable - only insert it's value).
I'd be perfectly happy if PHP's "anonymous" functions had the nice
syntax and no funky weird stuff about closure, a la
eval/create_function, personally.
I don't need the closures, but when I need a quickie anon function in
PHP, I just want something less ugly than create_function.
That's just my personal preference, of course.
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
Richard Lynch wrote:
I'd be perfectly happy if PHP's "anonymous" functions had the nice
syntax and no funky weird stuff about closure, a la
eval/create_function, personally.
While the discussion about closures and how to emulate them was
interesting I think Richard hits the nail on the head.
- Keep it simple as in Wez' patch.
- Maybe make it return a callback array (object, method) if used with
class to be able to use $this. - Maybe add $_SCOPE a la Andi's proposal if you really think it's
worthwhile.
My two cents,
- Chris
Can't you just take the body of "create_function" with the syntax of
the patch, and marry those two?
I already explained why this can't work, in this very thread. At least
not without hacking { and } to work (mostly) like " in this context.
How does the current create_function handle this same scope issue?
create_function()
takes a string. This string is interpolated at
runtime. There's an obvious distinction between local variables (they
look like $something within the string, and parent vars: they look like
'. $var .' )
S
Richard Lynch wrote:
I suspect that you could get away with JUST using global and/or static
as they exist now, not introduce yet another scoping keyword, and
anything that NEEDS to be done with an anonymous function can be
done.Does anybody really NEED a variable whose scope is non-global and
captured at the time of the func definition, carried over beyond the
scope of that until it's executed?...Somehow I think you're just complicating it "because you can" rather
than because anybody really NEEDS this.
Objects provide for functions with state (methods and properties), in a
way that doesn't cause headaches with scoping. So although I would love
the convenience of closures in certain places, I can't argue that there
is a NEED for them.
--
Chad Daelhousen
I've been programming for about 15 years, but it's only in the last
couple that I've come to a real understanding of it all.
I think the anonymous name having metadata about the FILE LINE
COLUMN would be pretty nifty for error messages and debuggers...
I'm a bit tired of seeing "Error: blah blah in Unknown on line: 0"
personally. :-)
This presumes somebody would take the effort to de-construct that
metadata for a better error message, but better to have it available
and possible to be done someday than "impossible"
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
My implementation preserves this information.
--Wez.
I think the anonymous name having metadata about the FILE LINE
COLUMN would be pretty nifty for error messages and debuggers...I'm a bit tired of seeing "Error: blah blah in Unknown on line: 0"
personally. :-)This presumes somebody would take the effort to de-construct that
metadata for a better error message, but better to have it available
and possible to be done someday than "impossible"--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
I think the anonymous name having metadata about the FILE LINE
COLUMN would be pretty nifty for error messages and debuggers...I'm a bit tired of seeing "Error: blah blah in Unknown on line: 0"
personally. :-)
I'd say if it's compiled then the compiler would put there file and line
numbers too, just as for the regular function.
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Am 19.03.2007 um 00:41 schrieb Wez Furlong:
We've been daydreaming about the ability to do something like this
in PHP:$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabeticallySo, the question is, do we want this in PHP?
Oh yes. Please. Please. Please :)
David
We've been daydreaming about the ability to do something like this in
PHP:
I don't have any objections, the only requirement from me is that it should be covered by tests as much as possible.
So I would like to encourage people to write tests to support the patch.
If all the people saying "yes, please" write a test case and send it to the list, the coverage would be pretty good, I guess.
Oh, and of course we can't include it into 5.2, it's only for HEAD (and maybe for 5.3, that's up to Ilia).
--
Wbr,
Antony Dovgal
Wez Furlong wrote:
So, the question is, do we want this in PHP?
Yes, please. (It might even make my userland implementation of of CLOS-
style generic functions easier.)
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
We've been daydreaming about the ability to do something like this in
PHP:$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabetically
I'd LOVE it if there was SOME difference between this and a normal
'function' definition...
I guess we're kind of stuck with 'create_function' being the mess that
it is.
But perhaps something like 'temp_function' or 'local_function' or
'lexical_closure' or something similar. Even 'horse' [*] would be
fine by me.
I think it muddies things too much to have it just be 'function' with
no name after it.
+1
- [sings] "In the desert, on a horse with no name"
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
We've been daydreaming about the ability to do something like this in
PHP:$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabeticallyI'd LOVE it if there was SOME difference between this and a normal
'function' definition...I guess we're kind of stuck with 'create_function' being the mess that
it is.But perhaps something like 'temp_function' or 'local_function' or
'lexical_closure' or something similar. Even 'horse' [*] would be
fine by me.I think it muddies things too much to have it just be 'function' with
no name after it.+1
A function with a name is no longer anonymous ;)
Cheers,
Rob.
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting |
| a powerful, scalable system for accessing system services |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for |
| creating re-usable components quickly and easily. |
`------------------------------------------------------------'
We've been daydreaming about the ability to do something like this
in
PHP:$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabeticallyI'd LOVE it if there was SOME difference between this and a normal
'function' definition...I guess we're kind of stuck with 'create_function' being the mess
that
it is.But perhaps something like 'temp_function' or 'local_function' or
'lexical_closure' or something similar. Even 'horse' [*] would be
fine by me.I think it muddies things too much to have it just be 'function'
with
no name after it.+1
A function with a name is no longer anonymous ;)
I am not suggesting that there be a name.
I am suggesting that the reserved keyword for an anonymous function
should not be 'function', the same as a normal function.
--
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some starving artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?
Richard Lynch wrote:
We've been daydreaming about the ability to do something like this
in
PHP:$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabetically
I'd LOVE it if there was SOME difference between this and a normal
'function' definition...I guess we're kind of stuck with 'create_function' being the mess
that
it is.But perhaps something like 'temp_function' or 'local_function' or
'lexical_closure' or something similar. Even 'horse' [*] would be
fine by me.I think it muddies things too much to have it just be 'function'
with
no name after it.+1
A function with a name is no longer anonymous ;)I am not suggesting that there be a name.
I am suggesting that the reserved keyword for an anonymous function
should not be 'function', the same as a normal function.
I don't have anything against 'function', I think JS uses the same
syntax - function without a name. If you change it to something
different, e.g 'callback', then you loose the information that it is
actually a function
$error_func = callback($msg) {
file_put_contents('php://stderr',"Error: $msg\n");
}
vs.
$error_func = function($msg) {
file_put_contents('php://stderr',"Error: $msg\n");
}
The second one looks better for me.
Am 20.03.2007 um 15:24 schrieb Daniel Rozsnyo:
A function with a name is no longer anonymous ;)
I am not suggesting that there be a name.
I am suggesting that the reserved keyword for an anonymous function
should not be 'function', the same as a normal function.I don't have anything against 'function', I think JS uses the same
syntax - function without a name. If you change it to something
different, e.g 'callback', then you loose the information that it
is actually a function$error_func = callback($msg) {
file_put_contents('php://stderr',"Error: $msg\n");
}vs.
$error_func = function($msg) {
file_put_contents('php://stderr',"Error: $msg\n");
}The second one looks better for me.
what about "lambda", like in Python?
David
what about "lambda", like in Python?
To most people without CS theory background lambda does not tell
anything, to people that have this background lambda reminds of LISP -
and I'm not sure this is better :)
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Am 20.03.2007 um 23:42 schrieb Stanislav Malyshev:
what about "lambda", like in Python?
To most people without CS theory background lambda does not tell
anything, to people that have this background lambda reminds of
LISP - and I'm not sure this is better :)
Excellent! That means people will maybe look it up to learn what a
lambda is before they use it, just what PHP needs ;)
Seriously though, my suggestion is nonsense because anonymous
functions in PHP wouldn't be restricted to a single expression, which
is the case with lambdas.
David
Yes, with whipped cream on top.
-Andrei
So, the question is, do we want this in PHP?