TOC

PHP 中 foreach 循环赋值给引用的一个特性(坑)

复现方法

创建一个存文本文件,命名为:test.php,内容如下:

<?php

$menu = [
    1 => ['id' => 1, 'name' => 'a', 'child' => []],
    2 => ['id' => 2, 'name' => 'b', 'child' => []],
];

foreach ($menu as &$submenu) {
    $submenu['class'] = empty($submenu['child']) ? '' : 'hasChild';
}

print_r($menu);

print str_repeat('-', 80) . "\n";

foreach ($menu as $submenu) {
    print_r($submenu);
}
?>

命令行中运行:

php -f test.php

得到以下输出:

Array
(
    [1] => Array
        (
            [id] => 1
            [name] => a
            [child] => Array
                (
                )

            [class] =>
        )

    [2] => Array
        (
            [id] => 2
            [name] => b
            [child] => Array
                (
                )

            [class] =>
        )

)
--------------------------------------------------------------------------------
Array
(
    [id] => 1
    [name] => a
    [child] => Array
        (
        )

    [class] =>
)
Array
(
    [id] => 1
    [name] => a
    [child] => Array
        (
        )

    [class] =>
)

可以发现,第二个 foreach 中的输出是错误的。

来自官网的说明

<?php
$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 )
?>

参考