刚解决了一个 BRN 的诡异 bug: 玩家控制系统里会重复出现同一个玩家的数据,占用的键却是其他人的. 经过一番排查定位到了一段 foreach 语句附近. 抽象后的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php $b = array(); function process(&$value) { $GLOBALS['b'][] = &$value; } $a = array(0, 1, 2, 3, 4); foreach($a as $key => $value){ process($value); } var_dump($b); ?> |
输出:
1 2 3 4 5 6 7 |
array(5) { [0]=> &int(4) [1]=> &int(4) [2]=> &int(4) [3]=> &int(4) [4]=> &int(4) } |
然而,把 foreach 中的 $value 加上引用符号以后则问题消失,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php $b = array(); function process(&$value) { $GLOBALS['b'][] = &$value; } $a = array(0, 1, 2, 3, 4); foreach($a as $key => &$value){ process($value); } var_dump($b); ?> |
输出:
1 2 3 4 5 6 7 |
array(5) { [0]=> &int(0) [1]=> &int(1) [2]=> &int(2) [3]=> &int(3) [4]=> &int(4) } |
个人分析是因为 foreach 会不停地对 $value 进行赋值,然而在 process 函数中处理的是对 $value 的引用,因此 $b 中存储的也全是对 $value 的引用,故最后 $b 中的所有元素都是 foreach 最后一次对 value 的赋值,也就是说如果在输出之前加一行 “$b[0] = 1” , 那么最后所有的元素都将是整形1;然而如果在 foreach 中本身就对 $value 赋引用,那么之后再赋给 $value 引用的时候就不会对之前的数据造成任何的变化. 说实话我对引用的赋值仍然不是很清楚,似乎 PHP 是不存在连环引用的= =
2013.12.30 更新
根据 Breezewish 的建议,这种写法是最靠谱的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php $b = array(); function process(&$value) { $GLOBALS['b'][] = &$value; } $a = array(0, 1, 2, 3, 4); foreach($a as $key => $value){ process($value); unset($value); } var_dump($b); ?> |
评论关闭。