foreach loop and reference of &$value
At the end of the first loop, $value
is pointing to the same place as $variable[3]
(they are pointing to the same location in memory):
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
Even as this loop is finished, $value
is still a reference that's pointing to the same location in memory as $variable[3]
, so each time you store a value in $value
, this also overwrites the value stored for $variable[3]
:
foreach ($variable as $key => $value);
var_dump($variable);
With each evaluation of this foreach, both $value
and $variable[3]
are becoming equal to the value of the iterable item in $variable.
So in the 3rd iteration of the second loop, $value
and $variable[3]
become equal to 4 by reference, then during the 4th and final iteration of the second loop, nothing changes because you're passing the value of $variable[3]
(which is still &$value
) to $value
(which is still &$value
).
It's very confusing, but it's not even slightly idiosyncratic; it's the code executing exactly as it should.
More info here: PHP: Passing by Reference
To prevent this behavior it is sufficient to add an unset($value);
statement after each loop where it is used. An alternative to the unset
may be to enclose the foreach
loop in a self calling closure, in order to force $value
to be local, but the amount of additional characters needed to do that is bigger than just unsetting it:
(function($variable){
foreach ($variable as $key => &$value) $value++;
})($variable);
This is a name collision: the name $value introduced in the first loop exists after it and is used in the second loop. So all assignments to it are in fact assignments to the original array. What you did is easier observed in this code:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
$value = 123; // <= here you alter the array!
var_dump($variable);
and you will see $variable[3]
as 123
.
One way to avoid this is, as others said, to unset ($value)
after the loop, which should be a good practice as recommended by the manual. Another way is to use another variable in the second loop:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
foreach ($variable as $key => $val);
var_dump($variable);
which does not alter your array.