I'm experiencing unusual behavior in PHP while iterating over arrays, and would love either an explanation or a confirmation that this is a bug.
For starters, here's the PHP version:
PHP 7.2.3 (cli) (built: Mar 8 2018 10:30:06) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.3, Copyright (c) 1999-2018, by Zend Technologies
Here's the sample script I created to replicate the behavior:
<?php
$example = [
[
'a' => 'A',
'b' => 'B',
],
[
'c' => 'C',
'd' => 'D',
],
[
'e' => 'E',
'f' => 'F'
]
];
foreach ($example as &$letters) {
foreach ($letters as &$letter) {
// Do nothing
}
}
print_r($example);
foreach ($example as $letters) {
print_r($letters);
}
?>
And here's the output:
Array
(
[0] => Array
(
[a] => A
[b] => B
)
[1] => Array
(
[c] => C
[d] => D
)
[2] => Array
(
[e] => E
[f] => F
)
)
Array
(
[a] => A
[b] => B
)
Array
(
[c] => C
[d] => D
)
Array
(
[c] => C
[d] => D
)
The unexpected behavior is that the second-to-last element replaces the last element only during the second iteration over the array. This is not seen, though, when printing the whole array.
This only happens if there's a nested foreach
loop where the values are used by reference. The length of the array does not seem to affect the behavior; the last element is always replaced with the second-to-last element.
Additionally, it appears that the problem is resolved if an unset($letters);
statement is added before the last foreach
loop.
Is this intentional, or a bug with PHP?
EDIT: See duplicate question above, and specifically this article, which demonstrates visually why the behavior is the way that it is.