PHP指针行为异常

时间:2018-08-29 10:17:38

标签: php pointers

在进行一个检查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循环,这表明数组在改变而没有被重新分配

2 个答案:

答案 0 :(得分:2)

根据PHP documentation

  

即使在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 areWhat 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>';  
}