Bug #74020 [Com]: Foreach-by-reference + assignment may recreate unexpected key references

From: Date: Tue, 23 Oct 2018 20:25:16 +0000
Subject: Bug #74020 [Com]: Foreach-by-reference + assignment may recreate unexpected key references
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-217667@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=74020&edit=1 ID: 74020 Comment by: fra dot martin at free dot fr Reported by: icarpenter at leadid dot com Summary: Foreach-by-reference + assignment may recreate unexpected key references Status: Verified Type: Bug Package: Scripting Engine problem PHP Version: 7.0.15 Block user comment: N Private report: N New Comment: This is probably the same issue, much more direct and very disturbing for me. These two simple foreach loops do nothing, they just use the same variable name, once by reference, once by value: the last array element always becomes a copy of the penultimate element! $items = [1,2,3]; foreach($items as &$item); foreach($items as $item); echo array_pop($items); Expected result: 3 Actual result: 2 Expected result: Previous Comments: ------------------------------------------------------------------------ [2017-01-31 15:28:00] icarpenter at leadid dot com While I agree that unsetting the $item is a best practice, the docs only really say you'll run into issues if you happen to do something with the reference variable. Since I'm not doing that here, one wouldn't expect references to get created when copying the original variable. Maybe the docs can be updated to say that foreach by reference will not only leave a variable with a reference to the last key in the array hanging around, but also the original array may contain references as well unless you unset the variable. ------------------------------------------------------------------------ [2017-01-31 08:57:37] requinix@php.net Note that var_dump on the array will show references. The first one looks like a bug as the reference was (supposedly) destroyed, however it comes back with the foo_copy=foo assignment. https://3v4l.org/DgJFP#v700 The second is not because $item is still a reference after the loop and when $mockCopy copies $mock it gets foo as a copy *of the reference*. https://3v4l.org/nrpE5 Adding unset($item) is the recommended solution. http://php.net/foreach ------------------------------------------------------------------------ [2017-01-31 03:08:04] icarpenter at leadid dot com Description: ------------ After a foreach-by-reference, an array may create references to keys if you create a copy of the original variable (either directly or indirectly via foreach) and then on that new variable, create a copy of a key to another key. The original key in that variable will then become a reference to the same key in the original array. In PHP 5.6 and 7.1, this can be avoided by either having the foreach run in a different scope, or unsetting the reference variable after the loop. PHP 7.0 exhibits this behavior regardless. Test script: --------------- https://3v4l.org/mHX7B (Triggers the bug in PHP 7.0) https://3v4l.org/VLuhn (Triggers the bug in PHP 5.6, 7.0, and 7.1) Expected result: ---------------- string(3) "foo" Actual result: -------------- string(3) "bar" ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=74020&edit=1

« previous php.bugs (#217667) next »