最小化分析代码:
$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);
}
~这里没有二维码和其他链接~
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.