2015-12-30 8 views
7

Questo è il codice che non capisco (come output).PHP Bug o il mio fraintendimento della lingua?

<?php 
$x = ['test1', 'test2', 'test3', 'test4']; 
echo "First FOREACH\n"; 
foreach ($x as &$y) 
{ 
    echo $y."\n"; 
} 
echo "\n\nSecond FOREACH\n"; 
foreach ($x as $y) 
{ 
    echo $y."\n"; 
} 

?> 

uscita:

First FOREACH 
test1 
test2 
test3 
test4 

Second FOREACH 
test1 
test2 
test3 
test3 

PS: Io corro sotto:

php -v 
PHP 5.6.11-1ubuntu3.1 (cli) 
Copyright (c) 1997-2015 The PHP Group 
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies 
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies 
+1

@ John, come fa eco l'argomento modificarlo? E, da quello che vedo quando si esegue il codice, il secondo ciclo esegue test1/test1. Qualcosa che l'OP potrebbe aver posto nella domanda se non fosse così odioso :-) – paxdiablo

+0

John .. non hai capito il problema. Per favore, esegui il codice e vedrai cosa intendo. PS: la nuova riga non si aggiunge affatto in questo codice, non vi è alcun cambiamento della variabile $ y da nessuna parte. –

+0

Come mostra l'output, l'elemento finale della matrice è interessato. @paxdiablo se hai una grande spiegazione, ci piacerebbe sentirlo. –

risposta

5

Dopo la prima istruzione foreach è necessario $y che punta all'ultimo elemento dell'array:

$x = ['test1', 'test2', 'test3', 'test4']; 
$y =& $x[3]; 

Ogni volta che si assegna un valore a $y matrice originale verrà modificato.

All'avvio del secondo avvio, a ogni iterazione il valore successivo da $x viene inserito in $y.Quindi, su ogni matrice originale iterazione sarà simile:

// first iteration 
$x = ['test1', 'test2', 'test3', 'test1']; 
// second iteration 
$x = ['test1', 'test2', 'test3', 'test2']; 
// third iteration 
$x = ['test1', 'test2', 'test3', 'test3']; 
// fourth iteration 
$x = ['test1', 'test2', 'test3', 'test3']; 
+0

Grazie per aver spiegato! –

5

E 'più di una caratteristica, è documentato nella foreach manpage

Avviso Il riferimento di un valore $ e l'ultimo elemento dell'array rimangono anche dopo il ciclo foreach. Si consiglia di distruggerlo con unset().

Ci sono alcune osservazioni pertinenti sulla pagina di manuale, ecco uno di loro http://php.net/manual/en/control-structures.foreach.php#111688

Maggiori informazioni su come questo accade qui http://schlueters.de/blog/archives/141-References-and-foreach.html

+1

Ho il sospetto che tu abbia il giusto collegamento doc, ma potresti spiegare in parole povere come questo risulti in ''test3'' che appare due volte nell'output dell'OP? –

+0

Ho incluso un * riferimento * a una spiegazione molto migliore di quella che potrei mai dare. –

0

E 'successo a causa del vostro primo ciclo, $y è ancora un punto di riferimento all'ultimo elemento dell'array, quindi viene sovrascritto ogni volta.

Quando si utilizza il riferimento in loop, è consigliabile distruggerlo utilizzando la funzione unset().

Per supporre, quando si crea una variabile Global, significa che si sta creando un riferimento.

E un altro esempio, quando si utilizza la parola chiave $this all'interno di un oggetto, stiamo creando il riferimento di questo oggetto anziché copiare nuovamente.

+1

L'OP non sta chiedendo cosa fare, chiede una spiegazione del comportamento descritto. – DanFromGermany

+0

@DanFromGermany: ho aggiornato secondo le mie conoscenze e ricerche. – devpro

0

Direi che si ottiene qualcosa del genere.

primo foreach test1 test2 Seconda foreach test1 test1

Poiché si utilizza la & con il vostro $ y nel primo foreach in modo da fare $ y un riferimento a $ x, l'intero array $ x. E $ y rimarrà un riferimento finché non lo annulli.
Quindi ...
Poiché si riutilizza $ y nel prossimo foreach, PHP imposta $ x due volte al primo elemento di $ y che è 'test1'. $ x sarà ['test1', 'test1'].

Fare sempre attenzione durante l'utilizzo dei riferimenti e disinserirli sempre quando non sono più necessari.

+0

Dopo che qualcuno ha modificato la mia domanda con 4 elementi, sembra che l'ultimo sia ripetuto, non il primo come inizialmente pensavo. –

0

Ok penso che accada in questo modo:

quando il primo ciclo è fatto. l'ultimo elemento della matrice è ancora riferimento con la variabile $y

pensare l'array come questo, quando il primo ciclo è fatto:

['test1', 'test2', 'test3', &'test4']

nota che ho inserito un & all'ultimo elemento perché fa riferimento alla variabile $y

Ora quando inizia il secondo ciclo. A ogni elemento di verrà fatto riferimento come $y e si ricorda nell'array $x che l'ultimo elemento è ancora referenziato dalla variabile $y dal ciclo.

Quindi l'ultimo elemento dell'array $x viene modificato in ciascuna iterazione del secondo ciclo. come $y

['test1', 'test2', 'test3', &'test1'] <-- $y as being first element, notice that the last element is also $y ['test1', 'test2', 'test3', &'test2'] $y being 'test2' ['test1', 'test2', 'test3', &'test3'] $y as 'test3' ['test1', 'test2', 'test3', &'test3'] $y being the last element which is 'test3'

Problemi correlati