在进行一个检查Laravel模型是否相互关联的项目时,我注意到PHP发生了一些(奇怪的)指针行为。下面是一个复制我发现的最小示例。
<?php
$arr = ['a', 'b', ['c']];
foreach($arr as &$letter) {
if (!is_array($letter)) {
$letter = [$letter];
}
}
dump($arr);
foreach($arr as $letter) {
dump($arr);
}
function dump(...$dump) {
echo '<pre>';
var_dump($dump);
echo '</pre>';
}
起初,我希望此响应中的转储全部返回相同的数据:
[ ['a'], ['b'], ['c'] ]
但这不是发生的事情,我得到了以下答复:
[ ['a'], ['b'], ['c'] ]
[ ['a'], ['b'], ['a'] ]
[ ['a'], ['b'], ['b'] ]
[ ['a'], ['b'], ['b'] ]
可以找到一个运行的示例here。
为什么指针以这种方式起作用?如何在第一个循环中更新$letter
,而不必执行$arr[$key] = $letter
?
编辑:由于人们似乎误解了为什么还有第二个foreach
循环,这表明数组在改变而没有被重新分配
答案 0 :(得分:2)
即使在foreach循环之后,仍保留$ value和最后一个数组元素的引用。建议通过unset()销毁它。
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
// Without an `unset($value)`, `$value` is still a reference to the last item: `$arr[3]`
foreach ($arr as $key => $value) {
// $arr[3] will be updated with each value from $arr...
echo "{$key} => {$value} ";
print_r($arr);
}
// ...until ultimately the second-to-last value is copied onto the last value
/* output:
0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 ) */
答案 1 :(得分:1)
首先:PHP没有指针,它具有引用。有关更多信息,请参见What references are和What references are not。
发生这种情况的原因是,在foreach循环之后的$letter
仍然持有对数组最后一个元素(即[c]
)的引用。因此,在第二个循环中,您不仅在循环时覆盖$letter
,而且覆盖它指向的引用。
要解决此问题,您需要在第一个循环后unset($letter)
:
$arr = ['a', 'b', ['c']];
foreach($arr as &$letter) {
if (!is_array($letter)) {
$letter = [$letter];
}
}
unset($letter); // this is important
dump($arr);
foreach($arr as $letter) {
dump($arr);
}
function dump(...$dump) {
echo '<pre>';
var_dump($dump);
echo '</pre>';
}