Após o primeiro loop foreach, $item
ainda é uma referência a algum valor que também está sendo usado por $arr[2]
. Portanto, cada chamada foreach no segundo loop, que não chama por referência, substitui esse valor e $arr[2]
, portanto , pelo novo valor.
Então, faça um loop 1, o valor e $arr[2]
torne - se $arr[0]
, que é 'foo'.
Loop 2, o valor e $arr[2]
tornar - se $arr[1]
, que é 'bar'.
Loop 3, o valor e $arr[2]
se tornar$arr[2]
, que é 'bar' (por causa do loop 2).
O valor 'baz' é realmente perdido na primeira chamada do segundo loop foreach.
Depurando a saída
Para cada iteração do loop, ecoaremos o valor $item
e imprimiremos recursivamente a matriz$arr
.
Quando o primeiro loop é executado, vemos esta saída:
foo
Array ( [0] => foo [1] => bar [2] => baz )
bar
Array ( [0] => foo [1] => bar [2] => baz )
baz
Array ( [0] => foo [1] => bar [2] => baz )
No final do loop, $item
ainda está apontando para o mesmo local que $arr[2]
.
Quando o segundo loop é executado, vemos esta saída:
foo
Array ( [0] => foo [1] => bar [2] => foo )
bar
Array ( [0] => foo [1] => bar [2] => bar )
bar
Array ( [0] => foo [1] => bar [2] => bar )
Você notará como cada matriz de tempo coloca um novo valor $item
, também é atualizado $arr[3]
com o mesmo valor, pois ambos ainda apontam para o mesmo local. Quando o loop atingir o terceiro valor da matriz, ele conterá o valor bar
porque foi definido apenas pela iteração anterior desse loop.
Isso é um bug?
Não. Esse é o comportamento de um item referenciado, e não um bug. Seria semelhante a executar algo como:
for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }
Um loop foreach não é de natureza especial em que pode ignorar itens referenciados. É simplesmente definir essa variável para o novo valor sempre que você faria fora de um loop.