foreach引用的坑
今天在网上看到一段代码,讲了foreach引用的坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php $data = [1, 2, 3, 4]; foreach ($data as &$v) { $v = $v*$v; } print_r($data); foreach ($data as $v) { echo $v."\n"; } |
你认为会输出什么?
实际上数据结果是这样
1 2 3 4 5 6 7 8 9 10 11 | Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 ) 1 4 9 9 |
是不是有些意外?为什么最后会是两个9?
其实按照官网文档所说,使用foreach的时候,引用变量不会消除,所以,当第一个foreach执行完成后,$v仍然指向$data的最后一个元素
因为作用域的问题,$v实际上还是存在于符号表中,例如,代码改成这样
1 2 3 4 5 6 7 8 9 10 11 | <?php $data = [1, 2, 3, 4]; foreach ($data as &$v) { $v = $v*$v; } print_r($data); print_r($v); |
结果如下
1 2 3 4 5 6 7 8 | Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 ) 16 |
瞧,$v指向的是16,也就是最后一个元素
最后,根据官方对foreach 的定义:格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步
简单来说,就是先将数组当前值赋值给$v,然后再移动指针,如果$v是引用的话,就会直接覆盖掉旧值
这样说可能不明确,请看下面代码和输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php $data = [1, 2, 3, 4]; foreach ($data as &$v) { $v = $v*$v; } print_r($data); foreach ($data as $v) { print_r($data); echo $v."\n"; } |
这是输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 ) Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 1 ) 1 Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 4 ) 4 Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 9 ) 9 Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 9 ) 9 |
如何,是不是一下子就看懂了?
虽然这个问题可能不常遇到,但现在仅作为一个坑记录在这里,防止以后踩坑忘了这个。