4

foreach ($data as &$item) 循环引用产生的问题

 2 years ago
source link: https://novnan.github.io/PHP/foreach_problems_caused_by_circular_references/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

foreach ($data as &$item) 循环引用产生的问题

发表于

2020-12-04 分类于 PHP

阅读次数:

Version

PHP version 7.4

最小化分析代码:

$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'

如何避免这个问题1:

foreach ($data as &$item) {

// 每次 loop 销毁$item (实际上只要在最后一次 loop 销毁即可,因此你可以把 unset 写到 foreach 后面,就是不是很好看)
unset($item);
}

如何避免这个问题2:

不使用引用


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK