13

对数组两次foreach的使用陷阱
对同一个数组两次foreach备注
这个问题是做小论坛的时候碰见的
如果单纯的对一个数组两次foreach是没什么问题的

clipboard.png

输出:

clipboard.png

如果在第一次foreach的时候,加了引用呢?

clipboard.png

输出:

clipboard.png

第二次的结果是 a b b,并不是数组的值
也就是说这种情况下,foreach循环最后一次的值和数组倒数第二个的值是一样的

clipboard.png

输出:

clipboard.png

为什么第二次结果是a b b呢?
foreach循环时,是通过移动数组内部指针来实现的
第一次foreach循环时,$v为引用变量
因而$v 与 $arr[2] 指向了同一个地址空间(共享变量值)
所以之后对$v的任何修改都会直接影响$arr
图解:

clipboard.png

第二次foreach的第一次循环时,$v被赋值为$arr[0],也就是a
而在第一次foreach结束时,$v最终指向了$arr[2],他们指向同一个地址空间
所以第二次foreach的第一次循环时,$v的值成了a,$arr[2]也就变成了a
第二次foreach的第二次循环时,$v的值成了b,$arr[2]也就变成了b
所以,数组$arr的值就成了a b b
所以第三次循环时,$v的值就成了b

上面说的明白,不过···
第二次foreach循环时,$v=$arr[0],按照之前说的,$v的指向不是指向了$arr[0]吗?
也就是说$v和$arr[0]指向同一内存地址,因为$arr和$v都没有发生值的变化
这里我们需要先了解一个知识点:

clipboard.png

结果:
1
2
2

clipboard.png

结果:
2
2
2

主要是这代码的运行结果:
我以为上面的代码中$v和$b应该指向同一zval,而$a的值不会被改变,但事实并非这样
是不是说一个变量的引用(&)没有消失,对这个变量重新赋值(非引用)其它变量的时候,其内存地址不会发生变化,也就是该变量的引用、指向内存地址的那条线不会改变,只是值变化

clipboard.png

结果:
1
2
2

clipboard.png

结果:
1
2
2

所以,结果才会这样

clipboard.png

输出:

clipboard.png

那现在又有这样一个疑虑,理论上在第二次foreach循环中,不会拷贝数组,这里$arr的值虽然发生了变化,但并不是直接通过$arr[$k]这样的方式去改变的,而是$v的值被改变,$v是个临时变量,间接的影响到了$arr数组的值,所以数组不会拷贝
(目前没想到更有说服力的理由)

三种解决方案:
① 第二次foreach循环,别用$v了
② 第二次foreach循环之前,unset($v)
$v的引用在 foreach 循环之后仍会保留。建议使用unset()将其销毁
③ 第二次循环也用&


web360
836 声望28 粉丝

大家都是凡人,难道你确定你是大神?


引用和评论

0 条评论