Comportamiento extraño de foreach cuando se usa referencia: foreach ($a as &$v) {...}
<?php
$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) { }
foreach ($a as $v) { }
print_r($a);
?>
Creo que es un programa normal pero este es el resultado que obtengo:
Array
(
[0] => a
[1] => b
[2] => c
[3] => c
)
¿Alguien puede explicarme esto?
Este es un comportamiento de PHP bien documentado. Consulte la advertencia en la página anterior de php.net.
Advertencia
La referencia de un valor $ y el último elemento de la matriz permanecen incluso después del bucle foreach . Se recomienda destruirlo mediante unset().
$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) { }
unset($v);
foreach ($a as $v) { }
print_r($a);
EDITAR
Intente obtener una guía paso a paso de lo que realmente está sucediendo aquí.
$a = array('a', 'b', 'c', 'd');
foreach ($a as &$v) { } // 1st iteration $v is a reference to $a[0] ('a')
foreach ($a as &$v) { } // 2nd iteration $v is a reference to $a[1] ('b')
foreach ($a as &$v) { } // 3rd iteration $v is a reference to $a[2] ('c')
foreach ($a as &$v) { } // 4th iteration $v is a reference to $a[3] ('d')
// At the end of the foreach loop,
// $v is still a reference to $a[3] ('d')
foreach ($a as $v) { } // 1st iteration $v (still a reference to $a[3])
// is set to a value of $a[0] ('a').
// Because it is a reference to $a[3],
// it sets $a[3] to 'a'.
foreach ($a as $v) { } // 2nd iteration $v (still a reference to $a[3])
// is set to a value of $a[1] ('b').
// Because it is a reference to $a[3],
// it sets $a[3] to 'b'.
foreach ($a as $v) { } // 3rd iteration $v (still a reference to $a[3])
// is set to a value of $a[2] ('c').
// Because it is a reference to $a[3],
// it sets $a[3] to 'c'.
foreach ($a as $v) { } // 4th iteration $v (still a reference to $a[3])
// is set to a value of $a[3] ('c' since
// the last iteration).
// Because it is a reference to $a[3],
// it sets $a[3] to 'c'.
El primer bucle foreach no realiza ningún cambio en la matriz, tal como es de esperar. Sin embargo, hace $v
que se le asigne una referencia a cada uno de $a
los elementos de , de modo que, cuando finaliza el primer ciclo, $v
es, de hecho, una referencia a $a[2]
.
Tan pronto como comienza el segundo ciclo, $v
ahora se asigna el valor de cada elemento. Sin embargo, $v
ya es una referencia $a[2];
, por lo tanto, cualquier valor que se le asigne se copiará automáticamente en el último elemento de la matriz.
Por lo tanto, durante la primera iteración, $a[2]
se convertirá en cero, luego en uno y luego en uno nuevamente, siendo efectivamente copiado sobre sí mismo. Para resolver este problema, siempre debes desarmar las variables que usas en tus bucles foreach por referencia o, mejor aún, evitar usar las primeras por completo.