简单分析一下 PHP 中`foreach ($data as &$item) `循环引用产生的问题
資深大佬 : JJstyle 2
最小化分析代码:
$data = ['foo', 'bar']; foreach ($data as &$item) { } foreach ($data as $item) { } print_r($data);
输出结果:
Array ( [0] => 'foo' [1] => 'foo' )
我们可以发现,$data
的值 ~~莫名奇妙~~ 变了,而它只是经过了两个空循环而已,发生了什么?!
下面我来一行行代码分析产生这个问题的原因:
先总结一下 PHP 中两条关于引用的两个规则:
- 给引用变量赋值,实际上是给引用所指向的变量赋值
- 一个引用变量可以被修改为对另外一个变量的引用
分析开始:
$data = ['foo', 'bar']; // 循环开始,$item 变量不存在,新建一个$item 变量,且是一个引用变量,它不指向任何变量地址 foreach ($data as &$item) { // loop 1: 执行了 $item = &$data[0];$item 指向 $data[0] 的地址 // loop 2: 执行了 $item = &$data[1];$item 指向 $data[1] 的地址 } // 提示:这个循环没有改变 $data 的数据,只是 $item 依然指向第二个元素 的地址 // 循环开始,$item 变量存在,不会新建变量 foreach ($data as $item) { // loop 1: 执行了 $item = $data[0];$item 所指向的变量(即 第二个元素)的值被修改为$data[0](即'foo'),这里已经导致了$data 两个元素都等于 'foo' // loop 2: 执行了 $item = $data[1];由于$item 指向的是$data[1],实际上相当于执行$data[1] = $data[1],没有任何意义 } // 最后$data 中的两个元素都是 'foo'
如何避免这个问题:
foreach ($data as &$item) { // 每次 loop 销毁$item (实际上只要在最后一次 loop 销毁即可,因此你可以把 unset 写到 foreach 后面,就是不是很好看) unset($item); }
~这里没有二维码和其他链接~
大佬有話說 (21)