2011-10-26 2 views
9

Ho una domanda su PHP e sull'uso di puntatori e variabili.Puntatore PHP e conflitto variabile

Il seguente codice produce qualcosa che non mi sarei aspettato:

<?php 
$numbers = array('zero', 'one', 'two', 'three'); 

foreach($numbers as &$number) 
{ 
    $number = strtoupper($number); 
} 

print_r($numbers); 

$texts = array(); 
foreach($numbers as $number) 
{ 
    $texts[] = $number; 
} 

print_r($texts); 
?> 

L'uscita è la seguente

Array 
(
    [0] => ZERO 
    [1] => ONE 
    [2] => TWO 
    [3] => THREE 
) 
Array 
(
    [0] => ZERO 
    [1] => ONE 
    [2] => TWO 
    [3] => TWO 
) 

Avviso della 'due' che appare due volte nel secondo array.

Sembra che ci sia un conflitto tra i due cicli foreach, ognuno dei quali dichiara una variabile numero $ (una volta per riferimento e la seconda per valore).

Ma perché? E perché influenza solo l'ultimo elemento nel secondo foreach?

+0

possibile duplicato del [Strano comportamento di foreach] (http://stackoverflow.com/questions/4969243/strange-behavior-of-foreach) –

+1

Si prega di consultare qui: http://stackoverflow.com/questions/4969243/ strano-comportamento-di-foreach/4969518 # 4969518 per una spiegazione approfondita di questo comportamento. –

+0

+1 per una bella :) –

risposta

4

Il punto chiave è che PHP non ha puntatori.Ha references, che è un concetto simile ma diverso, e ci sono alcune sottili differenze.

Se si utilizza var_dump() invece di print_r(), è più facile da individuare:

$collection = array(
    'First', 
    'Second', 
    'Third', 
); 

foreach($collection as &$item){ 
    echo $item . PHP_EOL; 
} 

var_dump($collection); 

foreach($collection as $item){ 
    var_dump($collection); 
    echo $item . PHP_EOL; 
} 

... stampe:

First 
Second 
Third 
array(3) { 
    [0]=> 
    string(5) "First" 
    [1]=> 
    string(6) "Second" 
    [2]=> 
    &string(5) "Third" 
} 
array(3) { 
    [0]=> 
    string(5) "First" 
    [1]=> 
    string(6) "Second" 
    [2]=> 
    &string(5) "First" 
} 
First 
array(3) { 
    [0]=> 
    string(5) "First" 
    [1]=> 
    string(6) "Second" 
    [2]=> 
    &string(6) "Second" 
} 
Second 
array(3) { 
    [0]=> 
    string(5) "First" 
    [1]=> 
    string(6) "Second" 
    [2]=> 
    &string(6) "Second" 
} 
Second 

Si prega di notare il simbolo & che è rimasto l'ultimo elemento dell'array .

In sintesi, ogni volta che si utilizzano i riferimenti in un ciclo, è buona pratica per rimuoverli al termine:

<?php 

$collection = array(
    'First', 
    'Second', 
    'Third', 
); 

foreach($collection as &$item){ 
    echo $item . PHP_EOL; 
} 
unset($item); 

var_dump($collection); 

foreach($collection as $item){ 
    var_dump($collection); 
    echo $item . PHP_EOL; 
} 
unset($item); 

... stampa il risultato atteso ogni volta.

2

variabile $number viene inizializzata anche dopo ciclo, è necessario rompere il riferimento unset

questo codice funziona correttamente:

<?php 
$numbers = array('zero', 'one', 'two', 'three'); 

foreach($numbers as &$number) 
{ 
    $number = strtoupper($number); 
} 

print_r($numbers); 
unset($number); 

$texts = array(); 
foreach($numbers as $number) 
{ 
    $texts[] = $number; 
} 

print_r($texts); 
?> 

http://www.php.net/manual/en/language.references.unset.php

Quando si cancella un riferimento, è basta interrompere l'associazione tra nome variabile e contenuto variabile. Questo non significa che il contenuto variabile sarà distrutto.

... pensare a questo come analogo alla chiamata di scollegamento Unix.

http://uk.php.net/manual/en/control-structures.foreach.php

Warning merito foreach

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

2

È necessario interrompere il riferimento dopo il primo ciclo.

foreach($numbers as &$number) 
{ 
    $number = strtoupper($number); 
}  
unset($number); 

come precisato nella documentation:

Attenzione Riferimento di un valore $ e l'ultimo elemento dell'array rimane anche dopo il ciclo foreach. Si consiglia di distruggerlo con unset().

Inoltre, se si utilizza var_dump() al posto di print_r(), si noterà che l'ultimo elemento dell'array dopo il primo ciclo è un riferimento:

array(4) { 
[0]=> 
string(4) "ZERO" 
[1]=> 
string(3) "ONE" 
[2]=> 
string(3) "TWO" 
[3]=> 
&string(5) "THREE" 
} 

Se si seguono Stefan Gehrig di commenti sulla domanda, c'è un collegamento che spiega perfettamente questo comportamento: http://schlueters.de/blog/archives/141-References-and-foreach.html