2013-08-11 16 views
9

In un post sul blog "PHP Internals: When does foreach copy", Nikic ha dichiarato che in un codice come questo:Perché foreach copia l'array quando non lo abbiamo modificato nel ciclo?

Snippet 1

$array = range(0, 100000); 
foreach ($array as $key => $value) { 
    xdebug_debug_zval('array'); // array is not copied, only refcount is increased 
} 

foreach non copiare l'array perché l'unica cosa che foreach modifica su $array è il suo interno puntatore di array.

Ha anche precisato che in un codice come questo:

frammento 2

$array = range(0, 100000); // line 1 
test($array); 
function test($array) { 
    foreach ($array as $key => $value) { // line 4 
     xdebug_debug_zval('array'); // array is copied, refcount not increased 
     // ... 
    } 
} 

foreach copierà la matrice, poiché se così non fosse, la variabile $array in linea 1 sarebbe cambiato .

Tuttavia, l'unica cosa che foreach modifica merito $array è che è puntatore interno. Quindi perché importa se il puntatore dell'array interno della variabile $array nella riga 1 è cambiato? Non importava nel frammento 1, perché aveva importanza nel frammento 2?

Perché lo standard foreach deve copiare la matrice nello snippet 2, anche se non l'abbiamo modificata nel ciclo?

+1

Da quello che so, che potrebbe essere non molto, si array è sempre passa come una copia, perché non si passa come riferimento. – JorgeeFG

+1

@Jorge, il punto è il motivo per cui php è solo copiato (aumento del conto) in frammenti 1, ma copiato nel frammento 2? Perché non è possibile eseguire una copia soft nello snippet 2, poiché non c'è alcuna modifica all'array? – Pacerier

+0

@Pacerier http://php.net/manual/en/language.references.pass.php –

risposta

1

La tua domanda ha una risposta nell'articolo a cui sei collegato. Si è data nella sezione

Non riferimento, refcount> 1

con la spiegazione che una copia delle strutture è necessario perché il puntatore si muove, e ciò non deve pregiudicare l'esterno array.

+1

Puoi mostrare un esempio di come può fallire? Perché è importante se il puntatore interno della matrice esterna cambia? Nel primo frammento, anche il puntatore dell'array si sposta e non vi impone una copia cartacea. – Pacerier

+0

Se si assegna una variabile a una funzione, si prevede che la variabile rimanga invariata dopo il ritorno della funzione. Anche la modifica del puntatore dell'array è una modifica della variabile e questo non deve accadere! – Sven

+1

dici che cambiare il puntatore dell'array interno è anche una modifica della variabile. Allora perché il primo frammento non esegue una copia cartacea? Anche il primo frammento modifica l'array. Lo stato di '$ array' prima di' foreach' e dopo 'foreach' è diverso anche nel primo snippet. – Pacerier

1

Questo perché nel secondo caso, $ array viene passato di valore alla funzione test(). Quindi, una copia dell'array $ è stata creata all'interno della funzione e foreach() funziona sulla copia. Le cose saranno diverse se l'array $ viene passato facendo riferimento alla funzione test().

Per informazioni sul passaggio per valore vs passaggio per riferimento, see this question

+1

Una copia di '$ array' non è stata creata all'interno della funzione http://derickrethans.nl/talks/phparch-php-variables-article.pdf. Solo l'incremento aumenta come riportato da 'xdebug_debug_zval'. Il 'foreach' non funziona sulla copia, perché non è stata effettuata alcuna copia. – Pacerier