Comportamiento extraño de foreach cuando se usa referencia: foreach ($a as &$v) {...}

Resuelto Manish Trivedi asked hace 54 años • 3 respuestas
<?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?

Manish Trivedi avatar Jan 01 '70 08:01 Manish Trivedi
Aceptado

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'.
Mark Baker avatar Feb 11 '2011 13:02 Mark Baker

El primer bucle foreach no realiza ningún cambio en la matriz, tal como es de esperar. Sin embargo, hace $vque se le asigne una referencia a cada uno de $alos elementos de , de modo que, cuando finaliza el primer ciclo, $ves, de hecho, una referencia a $a[2].

Tan pronto como comienza el segundo ciclo, $vahora se asigna el valor de cada elemento. Sin embargo, $vya 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.

dimitis avatar Jul 03 '2015 09:07 dimitis