問題一
我們先來看一段代碼:
$a=[1,2,3];
foreach($a as &$v){
}
foreach($a as $v){
}
var_dump($a);
我們來看一下運行結(jié)果是什么
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(2)
}
是不是和大家想的不一樣。
我們注意到運行結(jié)果里面,數(shù)組的最后一個元素是帶有引用,這就是出現(xiàn)這樣結(jié)果的關(guān)鍵所在。
讓我們來分析一下運行過程,當(dāng)程序運行完第一個循環(huán)之后,由于循環(huán)的變量$v是引用類型,而在循環(huán)結(jié)束之后,變量 $v 會被保留下來,并且作為引用類型指向數(shù)組 $a 的最后一個元素。這樣在執(zhí)行第二個循環(huán)的時候,會將 $a[0]、$a[1]的值依次賦值給 $v, 也即 $a[2]。所以在最后一次循環(huán)之前,$a[2] 的值變成了 2。而最后一次循環(huán)的時候,并不會改變 $a[2]的值,這樣就得到了上面的結(jié)果。
總結(jié)
造成以上結(jié)果的主要原因是,如果循環(huán)使用的變量是引用類型的話,循環(huán)結(jié)束,這個變量會作為引用變量被保留下來,并且指向循環(huán)變量的最后一個元素。所以在循環(huán)外修改這個變量的話,會影響循環(huán)變量最后一個元素的值。
因此在寫代碼的時候,如果循環(huán)使用的變量是引用類型的話,在循環(huán)結(jié)束可以對變量進行 unset 操作,這樣就不會有這樣的問題了。
問題二
讓我們再來看一段代碼
$a=[1,2,3];
foreach($a as $v){
$a[2] = 0;
var_dump($a);
var_dump($v);
}
讓我們來看一下運行結(jié)果
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(1)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(2)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(3)
然我們稍微改一下代碼
$b = &$a[2];
foreach($a as $v){
$b = 0;
var_dump($a);
var_dump($v);
}
運行結(jié)果如下
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(1)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(2)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(0)
看出來不同了么?
對于第一段代碼 Demo,在數(shù)組循環(huán)開始之后,在循環(huán)中修改數(shù)組的值不會影響循環(huán);而如果有引用變量指向數(shù)組的元素,在循環(huán)中修改引用變量的值則會影響循環(huán)。