2010-07-22 15 views
159

tengo este código:PHP Pasar por referencia en foreach

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.PHP_EOL; 
} 

Puede alguien explicar por qué la salida es: cero uno dos dos.

De zend certificación guía de estudio.

+50

'unset ($ your_used_reference);' cada vez que utilice un 'foreach ($ var as & $ your_used_reference)'! – Wrikken

+3

gracias por el punto, pero solo quería entender la lógica de cómo funciona el segundo foreach. – Centurion

+9

¿Por qué $ not_used_reference (o $ v en la publicación OPs) no se desactivan automáticamente? ¿Su alcance es el foreach y no debería existir más allá? – Hurix

Respuesta

127

Porque en el segundo ciclo, $v sigue siendo una referencia al último elemento del conjunto, por lo que se sobrescribe cada vez.

Se puede ver así:

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.'-'.$a[3].PHP_EOL; 
} 

Como se puede ver, el último elemento de la matriz toma el valor corriente de bucle: 'cero', 'uno', 'dos', y entonces es sólo ' dos '...:)

+1

bien, esto significa que en la última iteración el último elemento o sigue siendo dos o se le asignan dos nuevamente, ¿por qué no tres por qué se detiene en last-1? :) – Centurion

+4

No se detiene. El último elemento de matriz se asigna con el valor de ciclo actual. Entonces se le asigna 'cero', luego 'uno', luego 'dos'. En la última iteración, se le asigna su propio valor, que es 'dos', debido a la iteración anterior. Entonces simplemente permanece 'dos'. – Macmade

+8

Después de mejorar la salida, pude entender: '$ v obtiene el elemento [0] (cero). $ a [3] ahora es cero $ v obtiene el artículo [1] (uno). $ a [3] es ahora uno $ v obtiene el artículo [2] (dos). $ a [3] ahora es dos $ v obtiene el artículo [3] (dos). $ a [3] ahora es dos ' – Eduardo

0

Porque si crea una referencia a una variable, todos los nombres para esa variable (incluido el original) SE HACEN REFERENCIAS.

+0

Si este es el caso, ¿por qué si cambia $ v a & $ v en el segundo ciclo, ¿cambia el resultado, es decir, se repite cero, uno, dos, tres? –

+0

porque cuando usa & $ v en el segundo ciclo, está cambiando la referencia de la variable. Por lo tanto, el problema se elimina. – dejavu

133

Tuve que pasar unas horas para descubrir por qué un [3] está cambiando en cada iteración. Esta es la explicación a la que llegué.

Existen dos tipos de variables en PHP: variables normales y variables de referencia. Si asignamos una referencia de una variable a otra, la variable se convierte en una variable de referencia.

por ejemplo en

$a = array('zero', 'one', 'two', 'three'); 

si hacemos

$v = &$a[0] 

el elemento 0 ª ($a[0]) se convierte en una variable de referencia. $v apunta hacia esa variable; por lo tanto, si realizamos algún cambio en $v, se reflejará en $a[0] y viceversa.

ahora si hacemos

$v = &$a[1] 

$a[1] se convertirá en una variable de referencia y $a[0] se convertirá en una variable normal (ya que nadie más está apuntando a $a[0] se convierte en una variable normal. PHP es lo suficientemente inteligente como para que sea una variable normal cuando nadie más está apuntando hacia ella)

Esto es lo que sucede en el primer bucle

foreach ($a as &$v) { 

} 

Después de la última iteración $a[3] es una variable de referencia.

Desde $v está apuntando a $a[3] cualquier cambio en $v resulta en un cambio a $a[3]

en el segundo bucle,

foreach ($a as $v) { 
    echo $v.'-'.$a[3].PHP_EOL; 
} 

en cada iteración como $v cambios, $a[3] cambios. (porque $v aún apunta a $a[3]).Esta es la razón por la cual $a[3] cambia en cada iteración.

En la iteración anterior a la última iteración, $v tiene asignado el valor "dos". Dado que $v apunta a $a[3], $a[3] ahora obtiene el valor 'dos'. Mantén esto en mente.

En la última iteración, $v (que apunta a $a[3]) ahora tiene el valor de 'dos', porque $a[3] se estableció en dos en la iteración anterior. two se imprime. Esto explica por qué 'dos' se repite cuando $ v se imprime en la última iteración.

+19

gracias por una explicación bien detallada – Vodaldrien

+2

Me encanta tu explicación, pero esta sigue siendo una de esas cosas que me confunde constantemente. Debo recordar desajustar a _stay_ cuerdo. :-) – liamvictor

+0

Bien explicado. ¡Gracias! – phpnerd

1

Encontré este ejemplo también complicado. Por qué en el segundo ciclo en la última iteración no pasa nada ($ v permanece 'dos'), es que $ v apunta a $ a [3] (y viceversa), por lo que no puede asignar valor a sí mismo, por lo que mantiene el anterior valor asignado :)

41

primer bucle

$v = $a[0]; 
$v = $a[1]; 
$v = $a[2]; 
$v = $a[3]; 

Sí! Actual $v = $a[3] posición.

segundo bucle

$a[3] = $v = $a[0], echo $v; // same as $a[3] and $a[0] == 'zero' 
$a[3] = $v = $a[1], echo $v; // same as $a[3] and $a[1] == 'one' 
$a[3] = $v = $a[2], echo $v; // same as $a[3] and $a[2] == 'two' 
$a[3] = $v = $a[3], echo $v; // same as $a[3] and $a[3] == 'two' 

porque $a[3] se asigna por el procesamiento antes.

+5

No pude entender lo que decían las otras respuestas hasta que leí esto. ¡Gracias! – thanksd

+0

Yo también :) tks !! – MarceloBoni

3

Este:

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 

} 

foreach ($a as $v) { 
    echo $v.PHP_EOL; 
} 

es la misma que

$a = array ('zero','one','two', 'three'); 

$v = &$a[3]; 

for ($i = 0; $i < 4; $i++) { 
    $v = $a[$i]; 
    echo $v.PHP_EOL; 
} 

O

$a = array ('zero','one','two', 'three'); 

for ($i = 0; $i < 4; $i++) { 
    $a[3] = $a[$i]; 
    echo $a[3].PHP_EOL; 
} 

O

$a = array ('zero','one','two', 'three'); 

$a[3] = $a[0]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[1]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[2]; 
echo $a[3].PHP_EOL; 

$a[3] = $a[3]; 
echo $a[3].PHP_EOL; 
12

Creo que este código muestra el procedimiento más claro.

<?php 

$a = array ('zero','one','two', 'three'); 

foreach ($a as &$v) { 
} 

var_dump($a); 

foreach ($a as $v) { 
    var_dump($a); 
} 

Resultado: (Take atención en la última matriz de dos)

array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(5) "three" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(4) "zero" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "one" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "two" 
} 
array(4) { 
    [0]=> 
    string(4) "zero" 
    [1]=> 
    string(3) "one" 
    [2]=> 
    string(3) "two" 
    [3]=> 
    &string(3) "two" 
} 
11

llegué aquí simplemente por accidente y la pregunta del OP tiene mi atención. Lamentablemente, no entiendo ninguna de las explicaciones de la parte superior. Me parece que todos lo saben, lo obtienen, lo acceden, simplemente no pueden explicarlo.

Por suerte, una oración pura a partir de la documentación de PHP en foreach hace que esta completamente claro:

Advertencia: de referencia de un $value y el último elemento de la matriz se mantienen incluso después de que el bucle foreach. Se recomienda destruirlo por unset().

7

Esta pregunta tiene muchas explicaciones, pero no hay ejemplos claros de cómo resolver el problema que causa este comportamiento. En la mayoría de los casos, es probable que desee el siguiente código en su pase con la referencia foreach.

foreach ($array as &$row) { 
    // Do stuff 
    // Unset 
    unset($row); 
} 
+0

La forma correcta de hacerlo. – VSG24

+0

No funcionó para mí, tuve que usar el habitual 'unset ($ row [$ k]);' en su lugar. – Boykodev

Cuestiones relacionadas