PHP foreach原理詳解

當 foreach 開始執行時,數組內部的指針會自動指向第一個單元。若是移動指針的結果超出了數組單元的末端,則退出循環。php

例子:

$array = [
    'name' => 'Jobs',
    'age'  => 50,
];

foreach ($array as $key => $value) {

    $value = 22;
	//賦值,可是沒有影響到$array[$key]位置的值,除非加上 $array[$key] = $value;
}

上面的foreach 對數組內的值沒影響。有時候咱們爲了在循環過程當中改變數組項的值,在foreach的時候變量入口能夠加個&符號,表示,循環過程當中使用數組中原來的值,而不是一個複製的值,如數組

$array = [
    'name' => 'Jobs',
    'age'  => 50,
];

foreach ($array as $key => &$value) {
    //直接改變數組$array[$key]位置的值
    $value = 22;
}

結果輸出對比:函數

Array
(
    [name] => Jobs
    [age] => 50
)


Array
(
    [name] => 22
    [age] => 22
)

緣由分析:

$key$value都是臨時變量,foreach的時候,把每一個數組單元的鍵分別賦值給$key,把每一個數組單元的值分別賦給$value,相等於$value=$arr[$key]$value=2僅僅是改變了$value的值(非&傳遞),並不會影響到$array[$key],天然也就不會影響到$arraydebug

而用第二種方法(引用)的時候,相等於$value=&$array[$key]$array[$key]$value指向同一內存地址,$value=2天然就改變了$array[$key]的值,也就改變了$array的值指針

循環時,$key$value都是臨時變量,只是賦值方式不一樣code

陷阱

陷阱:兩次循環使用一樣的臨時變量的狀況下,若是第一次循環使用的是引用,那麼在第二次循環中即便沒有加&符號,臨時變量也是引用。這個引用指向了數組中最後一個元素(循環到了最後一個元素結束)。內存

如:string

array = [
    'name' => 'php',
    'age' => 123,
];


//標記爲循環1:
 
foreach ($array as $key => &$value) {
    echo "key=$key, value=$value" . PHP_EOL;
}

//循環完後,最後一個元素  $value = &$array['age'], 這裏$value 和  $array['age'] 是引用關係,都是指向的同一個空間。


var_dump($array); 

輸出結果以下:

array(2) {
  ["name"]=>
  string(3) "php"
  ["age"]=>
  &int(123)
}


//標記爲循環2:

foreach ($array as $key => $value) {
    //第一次循環進來  $value=$array['name'],此時$value = 'php',因爲咱們開始的引用中,
     $value 和 $array['age'] 創建了引用,因此這裏改變了$value的值,
     其實就改變了 $array['name']的值,因此 $array['name'] = 'php',

    //之後的每次循環處理都和上面第一次相同

   //獲得的結果:其實每次循環賦值給$value的值,都是給「標記爲循環1」中的最後一個元素在賦值,也就是說數組中最後一個元素的值 = 數組中的倒數第2個元素的值

    echo "key=$key, value=$value" . PHP_EOL;
}

上面的 foreach循環中輸出結果以下:變量

key=name, value=php
key=age, value=123

key=name, value=php
key=age, value=php

總結:兩次循環使用一樣的臨時變量的狀況下,若是第一次循環使用的是引用,那麼在第二次循環中即便沒有加&符號,臨時變量也是引用。這個引用指向了數組中最後一個元素(循環到了最後一個元素結束)。,獲得的最後數據結果就是數組中最後一個元素的值 = 數組中的倒數第2個元素的值 (也就是說,最後2個元素的值相同,且爲到倒數第2個元素的處理值)。擴展

如何避免這個陷阱呢?

方法1:在第二次循環以前,unset($value)

方法2:第二次foreach的時候使用不一樣名字的臨時變量

擴:

另:查看一個變量是不是引用可使用xdebug_debug_zval函數(須要有xdebug擴展)。

xdebug_debug_zval的結果形如: value: (refcount=2, is_ref=1)=123

相關文章
相關標籤/搜索