PHP指针和变量冲突


PHP pointer and variable conflict

我有一个关于PHP和指针和变量的使用的问题。

下面的代码产生了一些我没有预料到的结果:

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

输出如下

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

注意'TWO'在第二个数组中出现了两次。

两个foreach循环之间似乎存在冲突,每个循环都声明一个$number变量(一次是引用,另一次是值)。

为什么?为什么它只影响第二个foreach中的最后一个元素?

关键是PHP没有指针。它有引用,这是一个相似但不同的概念,有一些微妙的区别。

如果使用var_dump()而不是print_r(),则更容易发现:

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

…打印:

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

请注意最后一个数组项中剩下的&符号。

总而言之,无论何时在循环中使用引用,最好在末尾删除它们:

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

…每次输出预期的结果

变量$number即使在循环后也被初始化,您需要通过unset打破引用

下面的代码可以正常工作:

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

当你取消对引用的设置时,你只是打破了变量名和变量内容之间的绑定。这并不意味着变量内容将被销毁。

…可以把它看作类似于Unix的unlink调用。

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

foreach

$value的引用和最后一个数组元素即使在foreach循环之后仍然存在。建议使用unset()销毁它。

应该在第一个循环之后中断引用。

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

如文档中所述:

$value的引用和最后一个数组元素仍然存在即使在foreach循环之后。建议通过设置().

同样,如果您使用var_dump()而不是print_r(),您会注意到第一个循环之后数组的最后一个元素是引用:

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

如果你关注Stefan Gehrig对问题的评论,有一个链接可以很好地解释这种行为:http://schlueters.de/blog/archives/141-References-and-foreach.html