引用的意外行为

时间:2014-06-03 17:49:59

标签: php foreach reference

我对引用有一些意想不到的行为:

foreach ($this->data as &$row)
{
        $row['h'] = 1;
}

foreach ($this->data as $id => $row)
{
     ... in some cases $row[$id] = $row;
}

结果是数组的最后一个元素被替换为数组的倒数第二个元素。它由以下代码修复:

foreach ($this->data as $key => $row)
{
     $this->data[$key]['h'] = 1;
}

不幸的是,我没有更多时间花在这上面。也许这是PHP的错误(PHP 5.5.9-1ubuntu4)或者我不了解引用的东西?

2 个答案:

答案 0 :(得分:1)

有一个完美的逻辑解释,这不是一个错误!

PHP 5引入了直接修改数组内容的可能性,方法是通过引用而不是值将每个元素的值赋值给迭代变量。请考虑此代码,例如:

$a = array (’zero’,’one’,’two’);

foreach ($a as &$v) {
}
foreach ($a as $v) {
}

print_r ($a);

很自然地认为,因为这个小脚本对数组没有任何作用,所以它不会影响它的内容......但事实并非如此!实际上,该脚本提供了以下输出:

Array
(
[0] => zero
[1] => one
[2] => one
)

如您所见,数组已更改,最后一个键现在包含值“one”。怎么可能?正如我们所期望的那样,第一个foreach循环不会对数组进行任何更改。但是,它确实会为$v分配对每个$a元素的引用,因此,当循环结束时,$v实际上是一个引用到$a[2]

第二个循环开始后,$v现在被赋予每个元素的值。但是,$v已经是对$a[2]的引用;因此,分配给它的任何值都将自动复制到数组的最后一个元素中!因此,在第一次迭代期间,$a[2]将变为零,然后是一个,然后再一次,有效地复制到自身。要解决此问题,您应该始终取消设置在引用foreach循环中使用的变量 - 或者更好的是,完全避免使用前者。

答案 1 :(得分:0)

通过引用循环遍历数组时,需要在for循环结束时手动释放引用,以避免像这样的奇怪行为。所以你的第一个foreach应该是:

foreach ($this->data as &$row)
{
    .... code ....
}
unset($row);

在这种情况下,unset仅销毁引用,而不是$row引用的内容。

请参阅PHP foreach documentation

中的警告