while tiempo recorrer multidimensional mismo for elementos asociativo array agregar php arrays loops reference

tiempo - Pase de PHP Foreach por referencia: ¿Duplicación de último elemento?(¿Error?)



recorrer dos array al mismo tiempo php (6)

Acabo de tener un comportamiento muy extraño con un simple script php que estaba escribiendo. Lo reduje al mínimo necesario para recrear el error:

<?php $arr = array("foo", "bar", "baz"); foreach ($arr as &$item) { /* do nothing by reference */ } print_r($arr); foreach ($arr as $item) { /* do nothing by value */ } print_r($arr); // $arr has changed....why? ?>

Esto produce:

Array ( [0] => foo [1] => bar [2] => baz ) Array ( [0] => foo [1] => bar [2] => bar )

¿Es esto un error o algún comportamiento realmente extraño que se supone que suceda?


Después del primer bucle foreach, $item sigue siendo una referencia a algún valor que también está siendo utilizado por $arr[2] . Entonces cada llamada foreach en el segundo ciclo, que no llama por referencia, reemplaza ese valor, y por lo tanto $arr[2] , con el nuevo valor.

Así que el ciclo 1, el valor y $arr[2] convierten en $arr[0] , que es ''foo''.
Loop 2, el valor y $arr[2] convierten en $arr[1] , que es ''bar''.
Loop 3, el valor y $arr[2] convierten en $arr[2] , que es ''bar'' (debido al bucle 2).

El valor ''baz'' en realidad se pierde en la primera llamada del segundo bucle foreach.

Depuración de la salida

Para cada iteración del ciclo, repetiremos el valor de $item y también imprimiremos de forma recurrente el array $arr .

Cuando se ejecuta el primer ciclo, vemos esta salida:

foo Array ( [0] => foo [1] => bar [2] => baz ) bar Array ( [0] => foo [1] => bar [2] => baz ) baz Array ( [0] => foo [1] => bar [2] => baz )

Al final del ciclo, $item sigue apuntando al mismo lugar que $arr[2] .

Cuando se ejecuta el segundo ciclo, vemos esta salida:

foo Array ( [0] => foo [1] => bar [2] => foo ) bar Array ( [0] => foo [1] => bar [2] => bar ) bar Array ( [0] => foo [1] => bar [2] => bar )

Notarás cómo cada matriz de tiempo agrega un nuevo valor en $item , también actualizó $arr[3] con ese mismo valor, ya que ambos siguen apuntando a la misma ubicación. Cuando el bucle llegue al tercer valor de la matriz, contendrá la bar valores bar ya que solo se ajustó a la iteración anterior de ese bucle.

¿Es un error?

No. Este es el comportamiento de un elemento al que se hace referencia, y no un error. Sería similar a ejecutar algo como:

for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }

Un bucle foreach no es de naturaleza especial en el que puede ignorar elementos referenciados. Es simplemente establecer esa variable al nuevo valor cada vez que lo haría fuera de un bucle.


El comportamiento correcto de PHP debería ser un error de AVISO en mi opinión. Si una variable referenciada creada en un bucle foreach se usa fuera del bucle, debe generar un aviso. Muy fácil caer en este comportamiento, muy difícil de detectar cuando sucedió. Y ningún desarrollador leerá la página de documentación foreach, no es una ayuda.

Debería unset() la referencia después de su ciclo para evitar este tipo de problema. unset () en una referencia simplemente eliminará la referencia sin dañar los datos originales.


Si bien esto puede no ser oficialmente un error, en mi opinión lo es. Creo que el problema aquí es que esperamos que $item salga del alcance cuando salga el bucle como lo haría en muchos otros lenguajes de programación. Sin embargo, ese no parece ser el caso ...

Este código ...

$arr = array(''one'', ''two'', ''three''); foreach($arr as $item){ echo "$item/n"; } echo $item;

Da la salida ...

one two three three

Como ya han dicho otras personas, estás sobrescribiendo la variable referenciada en $arr[2] con tu segundo ciclo, pero solo está sucediendo porque $item nunca salió del alcance. ¿Qué piensan ustedes ... error?



eso es porque utilizas la directiva ref (&). el último valor será reemplazado por el segundo ciclo y dañará su matriz. la solución más simple es usar un nombre diferente para el segundo ciclo:

foreach ($arr as &$item) { ... } foreach ($arr as $anotherItem) { ... }


$item es una referencia a $arr[2] y está siendo sobreescrito por el segundo bucle foreach como se señala en animuson.

foreach ($arr as &$item) { /* do nothing by reference */ } print_r($arr); unset($item); // This will fix the issue. foreach ($arr as $item) { /* do nothing by value */ } print_r($arr); // $arr has changed....why?