引用
入门。
放弃?
先创建一个简单的数组:
php > $a = array(1, 2, 3);
然后用 foreach 逐个打印出来,先试试用引用
php > foreach ($a as &$v) { print $v."\n"; }
1
2
3
好像没问题,再试试值传递:
php > foreach ($a as $v) { print $v."\n"; }
1
2
2
为什么最后一个是 2 而不是 3?!
进阶!
下面我们看看分解动作
第一个 foreach
相当于先让$v指向 a 的第一个值,$a[0]就变成了引用,注意下面打印结果中的[0]=>&int(1)
php > foreach ($a as &$v) { var_dump($a); break; }
array(3) {
[0]=>
&int(1)
[1]=>
int(2)
[2]=>
int(2)
}
下一步 v 指向 a[1], a[1]就变成了引用,
php > foreach ($a as &$v) { if ($v === 2) {var_dump($a); break; } }
array(3) {
[0]=>
int(1)
[1]=>
&int(2)
[2]=>
int(2)
}
而由于没有任何变量指向 a[0],a[0] 恢复正常,为了演示这一点,可以另创建一个变量指向 a[0],那即使 v 不再指向 a[0],a[0] 依然是引用变量:
php > $t = &$a[0];
php > foreach ($a as &$v) { if ($v === 2) {var_dump($a); break; } }
array(3) {
[0]=>
&int(1)
[1]=>
&int(2)
[2]=>
int(2)
}
如果你运行了上面的语句记得先把 t 扔掉:
php > unset($t);
当三个循环都结束的时候,v 并没有消失,a[2]仍然是引用变量
php > foreach ($a as &$v) {}
php > var_dump($a);
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(2)
}
php > var_dump($v);
int(2)
第二个 foreach
第一步$v仍然指向$a[2],这时foreach相当于运行$v = $a[0],结果$a[2]被赋上了$a[0]的值:
php > foreach ($a as $v) { var_dump($a[2]); break; }
int(1)
$a已经不是原来的[1, 2, 3]了,变成了[1, 2, 1]。第二步类似的,foreach让$v = $a[1], 也就是$a[2] = $a[1], $a[2]的值再次改变,成了 2:
php > foreach ($a as $v) { if ($v === 2) { var_dump($a[2]); break; } }
int(2)
$a变为[1, 2, 2]。
第三步,$v = $a[2],也就是$a[2] = $a[2],所以$a和上一步相同,还是[1, 2, 2].
解决方法
每次使用引用后记得unset,否则会出现这样很隐蔽的 bug。
foreach ($a as &$v) {
// ...
}
unset($v);
更好的方法是,能不用引用就不要用引用...