當咱們使用foreach時,內部究竟發生了什麼(PHP5)?

如下全部結論均基於PHP5版本
看下面一段最基礎的foreach遍歷數組代碼。php

<?php 
$arr = array(‘a’,’b’,’c’);
foreach ($arr as $key=> $value) {
    echo $key,$value,’<br/>’; //output :  0a1b2c
}
?>

輸出爲’0a1b2c’天然沒有疑問,那麼此過程當中$arr,$key,$value到底是通過怎樣的運算,才輸出這個結果的呢?數組

其實foreach遍歷過程當中,並非直接操做$arr(原數組)的,而是會將$arr複製出一個$arrcopy(是一個$arr的一個複製品,我這裏以$arrcopy代替),foreach在遍歷過程當中操做的其實一直是$arrcopy。
注:關於$arrcopy這個值咱們是沒辦法提取出來的,由於這是我給他的命名,並無存在這個變量,可是foreach遍歷過程當中確實會產生這麼一個副本,這兒爲了方便講述我用$arrCopy表明。
Foreach遍歷大概的流程是這樣(僞代碼):函數

<?php 
//僞代碼
$arr = array('a','b','c');
/* foreach循環開始*/
//first loop
$arrCopy = $arr; //複製出一個待循環數組的副本,接下來都是操做這個副本
$key = currentKey($arrCopy); //將獲取到的值分配給$k;
$val = currentVal($arrCopy); //將獲取到的值分配給$v;
next($arrCopy);//移動副本數組的指針
$arr = $arrCopy;//將副本賦值回給$arr((主要是將指針同步移動))
//大括號內容
{
    echo $key,$value,’<br/>’;
}
//firt loop end

//second loop 
$key = currentKey($arrCopy); //將獲取到的值分配給$k;
$val = currentVal($arrCopy); //將獲取到的值分配給$v;
………
//seconde loop end
?>

這就是foreach代碼的運行流程,總結一句話就是foreach遍歷操做的時候並非原始數組,而是一個拷貝數組,可是每次循環的結尾都會將副本從新賦值回給原數組$arr = $arrCopy;。oop

如何證實個人說法呢?能夠用下面這段代碼檢驗。spa

<?php 
// $a = array('a','b','c');
 $arr = array('a','b','c');
foreach ($arr as $key=> $value) {
    $arr[] = 'd';
    print_r($arr);
    var_dump($key,$value);
}
?>

輸出結果爲:指針

//output:
Array
    (
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    )
    int(0)
    string(1) "a"
    Array
    (
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    [4] => d
    )
    int(1)
    string(1) "b"
    Array
    (
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    [4] => d
    [5] => d
    )
    int(2)
    string(1) "c"

同窗們看出來了嗎?
$arr數組的鍵值對一直在在增長,但是$key,$value的值到了int(2),string(1) 「c」就結束了,並無如咱們所料的將值爲d的那些鍵值對打印出來。
這兒就能證實,foreach遍歷過程操做的是$arr的副本($arrcopy)。code

對了,foreach使用過程當中還有一些小地方須要注意。
例如foreach遍歷數組的指針問題:blog

<?php 
$arr = array('a','b','c');
var_dump(current($arr)); //output:string(1) "a"
foreach ($arr as $key=> $value) {

}
var_dump(current($arr)); //output:bool(false)
?>

兩次輸出,不同的結果。爲何呢?由於foreach循環遍歷後的數組,該數組的指針是指向末尾的(此處的話指針就是在’c’的右邊),而且使用完畢後不會幫咱們復位,因此咱們var_dump(current($arr))爲 bool(false)。
那麼在這裏咱們須要特別注意,爲了保險起見咱們在foreach遍歷數組後,最好手動reset()一下數組,防止出錯:圖片

<?php 
$arr = array('a','b','c');
var_dump(current($arr)); //output:string(1) "a"
foreach ($arr as $key=> $value) {

}
reset($arr);
var_dump(current($arr)); / output:string(1) "a"
?>

這樣就正常了。同步

還有一點PHP手冊也提醒咱們了:
圖片描述
轉成代碼的意思就是:

<?php 
$arr = array('a','b','c');
foreach ($arr as $key=> $value) {

}
var_dump($key);
var_dump($value);
?>

Foreach遍歷後,$key和$value是真實存在的,最好使用後能手動unset()掉。

總結:foreach算是PHP裏面比較複雜的一個函數了,由於牽扯到PHP底層的C語言的結構體,引用(is_ref__gc),指針移動……,因此在使用foreach的時候必定要特別注意啊!

相關文章
相關標籤/搜索