2011-10-26 10 views
9

Tengo una pregunta sobre PHP y el uso de punteros y variables.Puntero PHP y conflicto variable

El siguiente código produce algo que no habría esperado:

<?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); 
?> 

La salida es la siguiente

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

Aviso el 'dos' que aparece dos veces en la segunda matriz.

Parece que hay un conflicto entre los dos bucles foreach, cada uno declarando una variable de $ number (una por referencia y la segunda por valor).

¿Pero por qué? ¿Y por qué afecta solo el último elemento en el segundo foreach?

+0

posible duplicado de [Comportamiento extraño de foreach] (http://stackoverflow.com/questions/4969243/strange-behavior-of-foreach) –

+1

Por favor, mira aquí: http://stackoverflow.com/questions/4969243/ strange-behavior-of-foreach/4969518 # 4969518 para una explicación más detallada de este comportamiento. –

+0

+1 por uno agradable :) –

Respuesta

4

El punto clave es que PHP no tiene punteros.Tiene references, que es un concepto similar pero diferente, y hay algunas diferencias sutiles.

Si utiliza var_dump() en lugar de print_r(), que es más fácil de detectar: ​​

$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; 
} 

... impresiones:

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 

Tenga en cuenta el símbolo & que queda en el último elemento de la matriz .

En resumen, cada vez que utilice referencias en un bucle, es una buena práctica para eliminarlos al final:

<?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); 

... imprime el resultado esperado cada vez.

2

variable de $number se inicia incluso después de bucle, es necesario romper la referencia por unset

este código funciona correctamente:

<?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

Cuando borra una referencia, simplemente rompa el enlace entre el nombre de la variable y el contenido de la variable. Esto no significa que se destruirá el contenido variable.

... piense en esto como análogo a la llamada de desvinculación de Unix.

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

Advertencia sobre foreach

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

2

Debe interrumpir la referencia después del primer ciclo.

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

como se indica en documentation:

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

Además, si se utiliza var_dump() en lugar de print_r(), usted notará que el último elemento de la matriz después del primer bucle es una referencia:

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

Si sigue Stefan Gehrig comentarios sobre la pregunta, hay un enlace que explica perfectamente este comportamiento: http://schlueters.de/blog/archives/141-References-and-foreach.html