引用
入门。
放弃?
先创建一个简单的数组:
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);
更好的方法是,能不用引用就不要用引用...