PHP指针和变量冲突

时间:2011-10-26 09:08:36

标签: php pointers

我对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中的最后一个元素?

3 个答案:

答案 0 :(得分:4)

关键是PHP没有指针。它有references,这是一个相似但不同的概念,并且有一些细微的差别。

如果您使用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);

...每次打印预期结果。

答案 1 :(得分:2)

变量$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的警告

     

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

答案 2 :(得分:2)

你应该在第一次循环后打破引用。

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

documentation中所述:

  

警告引用$ 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