【问题标题】:Unexpected behavior with references引用的意外行为
【发布时间】:2014-06-03 17:49:59
【问题描述】:
我对引用有一些意外行为:
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) 的错误或我不知道的参考?
【问题讨论】:
标签:
php
foreach
reference
【解决方案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
)
如您所见,数组已更改,最后一个键现在包含值“一”。这怎么可能?正如我们所期望的那样,第一个foreach 循环不会对数组进行任何更改。但是,它确实会导致为$v 分配对$a 的每个元素的引用,因此,当循环结束时,$v 实际上是对$a[2] 的引用。
当第二个循环开始时,$v 现在被分配了每个元素的值。但是,$v 已经是对$a[2] 的引用;因此,分配给它的任何值都将自动复制到数组的最后一个元素中!因此,在第一次迭代期间,$a[2] 将变为 0,然后变为 1,然后再次变为 1,被有效地复制到自身。要解决此问题,您应该始终取消设置您在按引用 foreach 循环中使用的变量,或者更好的是,完全避免使用前者。
【解决方案2】:
当通过引用循环数组时,您需要在 for 循环结束时手动放开引用,以避免像这样的奇怪行为。所以你的第一个foreach 应该是:
foreach ($this->data as &$row)
{
.... code ....
}
unset($row);
在这种情况下, unset 只是破坏引用,而不是 $row 引用的内容。
查看PHP foreach documentation中的警告