foreach中&引用问题

本文探讨了PHP中使用foreach循环时引用导致的数组元素意外修改问题,并通过示例代码详细解析了问题产生的原因及解决办法。

最近有同事碰到一个很怪异的场景,跑到我这里问,我也琢磨半天,结合百度搜索才明白原因。

先来看看问题代码:


$a = ['a'=>1,'b'=>['c'=>2],'d'=>3,'e'=>4];

foreach($a as $k=>&$v) {

}

print_r($a);

foreach($a as $k =>$v) {
    
}

print_r($a);

很简单的代码,但是输出很诡异:

Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => 4
)
Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => 3
)

看到没有,数组的最后一个元素被改变了。 看了网上别人的解释,琢磨半天,总算明白是个什么意思。

http://php.net/manual/zh/control-structures.foreach.php 这里,有一个警告:

Warning 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。

什么意思呢,就是在 foreach 遍历结束后,我们的临时变量 $k, $v 仍然保留,指向最后一个遍历元素。那么,如果我们的 $v 是一个引用的话,那在后面直接对其进行操作的话,是会产生问题的。所以,这里PHP建议你将其 unset 掉。

怎么理解呢?下面我们调整上上述代码,在循环体里面输出一下 $a 的值:

$a = [ 'a'=>1, 'b'=>[ 'c'=>2], 'd'=>3, 'e'=>4];

foreach($a as $k=>&$v) {

}

echo "after first round of foreach \$k = '$k ', \$v = '$v'" .PHP_EOL;

echo PHP_EOL.'the next round of foreach' .PHP_EOL;

foreach($a as $k=>$v) {
    echo PHP_EOL.'key: '.$k.PHP_EOL;
    print_r($a );
}

我们看一下输出:

after first round of foreach $k = 'e', $v = '4'

the next round of foreach

key: a
Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => 1
)

key: b
Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => Array
        (
            [c] => 2
        )

)

key: d
Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => 3
)

key: e
Array
(
    [a] => 1
    [b] => Array
        (
            [c] => 2
        )

    [d] => 3
    [e] => 3
)


在第一轮遍历结束后 $v 指向 $a 的最后一个元素的地址(引用),那么在第二轮遍历的时候,是会把 $a 的每个元素分别赋值给 $v,也就是 $a 的最后一个元素。 所以就产生了我们看到的场景。

这里,建议大家在使用foreach的时候慎用&,使用完后,要记得unset调这个变量。不然会产生各种诡异的问题。

转载于:https://my.oschina.net/sxl1010/blog/988642

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值