From: nate at frickenate dot com Operating system: Linux PHP version: 5.3.1 PHP Bug Type: Unknown/Other Function Bug description: lambda/anonymous functions do not have proper scope
Description: ------------ The way in which variables are passed to the inside of a lambda function via the 'use (...)' syntax is broken. The entire concept of "scope" or "closures" does not seem to apply in php whatsoever. Variables within a lambda are supposed to be resolved/looked up in the parent scope at runtime when the variable is actually accessed within the lambda function's code. It seems that php just dumbly creates a copy of the variable when it sees the definition of the lambda function with the 'use (...)' clause. Changes to the variable in the parent scope between the moment where the lambda is defined and the lambda function is called are not propagated. The worst part happens with objects. When passing in an object instance to a lambda, any changes to the original object in the parent scope after the lambda definition do affect the same object (problem 4 in reproduce code), but replacing the object altogether does not (problem 3 in reproduce code). I imagine this has to do with the php5 "fake references" that are used to pass objects around. I get the feeling this is just a horrible limitation of the devs having hacked a "best-possible" implementation of "lambdas" into a Zend codebase that can't handle proper scope lookup. If this is the case, it would be nice if the documentation could be updated to really nail home the fact that there is no scoping going on at all, and that quite literally all you get is a copy of the variable as it exists at the moment the lambda is defined (except for the strangeness going on with objects). It's unfortunate that the "solution" for the time being is to *always* pass in *every* variable as a reference, which results in expected output. But this requires creating a local copy within the lambda for every variable that one wants to modify without affecting the parent scope. :'( Reproduce code: --------------- <?php // problem 1: this should echo "Canada", not a php notice $fn = function () use ($country) { echo $country . "\n"; }; $country = 'Canada'; $fn(); // problem 2: this should echo "Canada", not "UnitedStates" $country = 'UnitedStates'; $fn = function () use ($country) { echo $country . "\n"; }; $country = 'Canada'; $fn(); // problem 3: this should echo "Canada", not "UnitedStates" $country = (object)array('name' => 'UnitedStates'); $fn = function () use ($country) { echo $country->name . "\n"; }; $country = (object)array('name' => 'Canada'); $fn(); // problem 4: this outputs "Canada". if this outputs "Canada", // then so should problem 2 above. otherwise this should be // just as broken as problem 2 and be outputting "UnitedStates" $country = (object)array('name' => 'UnitedStates'); $fn = function () use ($country) { echo $country->name . "\n"; }; $country->name = 'Canada'; $fn(); ?> Expected result: ---------------- If scope was actually handled properly, then the lookup of the "use (...)"'d variable would occur at the moment the variable is used within the lambda, resulting in the following output: Canada Canada Canada Canada Actual result: -------------- PHP Notice: Undefined variable: country in ... on line 5 UnitedStates UnitedStates Canada -- Edit bug report at http://bugs.php.net/?id=50980&edit=1 -- Try a snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=50980&r=trysnapshot52 Try a snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=50980&r=trysnapshot53 Try a snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=50980&r=trysnapshot60 Fixed in SVN: http://bugs.php.net/fix.php?id=50980&r=fixed Fixed in SVN and need be documented: http://bugs.php.net/fix.php?id=50980&r=needdocs Fixed in release: http://bugs.php.net/fix.php?id=50980&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=50980&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=50980&r=needscript Try newer version: http://bugs.php.net/fix.php?id=50980&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=50980&r=support Expected behavior: http://bugs.php.net/fix.php?id=50980&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=50980&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=50980&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=50980&r=globals PHP 4 support discontinued: http://bugs.php.net/fix.php?id=50980&r=php4 Daylight Savings: http://bugs.php.net/fix.php?id=50980&r=dst IIS Stability: http://bugs.php.net/fix.php?id=50980&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=50980&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=50980&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=50980&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=50980&r=mysqlcfg