PHP之foreach引用填坑

起因

看到一篇文章描(就是它)述了PHP的一个语法特点,用文字来描述就是如果对一个数组进行foreach引用遍历过后在对这个数组使用同样的变量进行一次普通foreach遍历会导致这个数组的值发生变化。
我这个描述可能还是不太清楚,直接上代码:
PHP
可以看到在循环当中没有任何代码,所以两次打印出来的数据肯定应该是一模一样的,然而结果总是让人意外:
结果
在这里插入图片描述
我当时就惊呆了!还能这样的?
文章中的解释只有一句话:因为数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留,在第二个循环的时候实际上是对之前的指针不断的赋值。看着这句话想了半天愣是没想明白,然后又找到了PHP关于foreach的文档:PHP 手册=>语言参考=>流程控制
文档里面也只是给了个警告提示:Warning:数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。原谅我,我真的没看懂…本来都不想去思考这个了,反正我平时也不会有这种骚操作,但是作为一个phper1,我的内心深处告诉我不能就这样算了,PHP的问题都搞不清楚还怎么在PHP界立足,世界上最好的语言都搞不好怎么去学习其他语言,想到这里我的手又不由自主的打开了搜索引擎…

经过

在我的一通搜索中终于找到了一篇文章:PHP foreach使用 &引用 的坑
PHP foreach使用 &引用 的坑
很认真的看了几遍,似乎有些眉目了,就是说在第一次foreach循环结束以后里面的变量$a并没有被销毁,而是保留了下来,并且依旧是一个引用2 变量。
明白了这个并没有解决我心中的疑虑:就算变量$a没有被销毁,那么在第二次的foreach也要被覆盖的,第一次循环$arr[2]被覆盖成了1,第二次循环$arr[2]被覆盖成了2,第三次循环$arr[2]被覆盖成了4,循环结束$arr[2]不还是4吗,咋打印出来就变成了2呢?
确实想不通,我在第二次循环中把$arr[2]打印出来看一看,来验证一次:
arr[2]
结果:
print
真是搞不懂第三次咋就变了,这个时候切记心浮气躁,静下心来捋一捋整个流程,从第一次循环结束开始:
前面说第一次循环结束后的的变量$a是引用1 ,怎么证明呢?那多简单,把变量$a的类型打印出来看下不就知道了,找了下有个gettype()函数,我们来试试:
gettype
看样子这不是我想要的结果…只有再去搜索一番了。
果然让我发现了一个新的函数xdebug_debug_zval(),这个函数需要装Xdebug扩展,关于这个函数的介绍可以看一下PHP官网:引用计数基本知识
引用计数基本知识
这个函数不仅会打印出来变量的类型和值,还会有两个额外信息:is_refrefcountis_ref表示这个变量是否为引用变量,refcount表示指向这个zval变量容器的变量(也称符号即symbol)个数。我们只需要看is_ref就可以了:
代码
结果:
结果
从结果中可以看到is_ref1true表示变量$a确实是引用变量,然后我们继续分析foreach循环过程中的数据变化:

  1. $arr[0]的值1赋值给$a,这时$a的引用即$arr[2]的值为1
  2. $arr[1]的值2赋值给$a,这时$a的引用即$arr[2]的值为2
  3. $arr[2]的值(注意了,第二步$arr[2]的值已经被覆盖为22赋值给$a,这时$a的引用即$arr[2]的值为2
  4. 此时$arr的值就是[1, 2, 2]了。

总结

经过这么一遍梳理总算是搞清楚怎么回事了,其实就是在第二次循环中通过赋值给引用变量改变了被循环数组的值,导致原数组值的变化,现在也理解了官方文档中那句警告是什么意思了。

参考文档


  1. 代码搬运工。 ↩︎ ↩︎

  2. 可以理解为指针类型。 ↩︎

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值