1. 程式人生 > >說說PHP中foreach引用的一個坑

說說PHP中foreach引用的一個坑

先來看看下面這段程式碼:

<?php 
    $arr = array('apple','banana','cat','dog');
    foreach($arr as $key=>$val)
    {
        //some code
    }

    echo $val;  //輸出dog
    echo $key;  //輸出3

    //下面對val進行賦值
    $val = 'e';
    print_r($arr);  //輸出Array ( [0] => apple [1] => banana [2] => cat [3] => dog )

說明:在上面的foreach迴圈中,當迴圈結束後,$key和$val變數都不會被自動釋放掉。值會被儲存下來。而且此時修改$val的值不會影響$arr。

引用:如果想在遍歷陣列的過程中修改陣列的元素,可以在foreach中對$val使用引用。此時被引用的元素$val指向當前陣列元素的記憶體地址,即共享一段記憶體地址。因此修改$val的值會同時改變$arr[$key]的值。

再來看看下面一段在foreach中使用引用的程式碼,這是最近在專案中遇到的一種情況:

<?php 
    $arr = array('apple','banana','cat','dog');
    //在foreach中使用引用
    foreach($arr as $key => &$val)
    {
        $val = 'new value';
    }

    echo $val;  //輸出new value
    echo $key;  //輸出3

    $val = 'egg';
    print_r($arr);  //輸出Array ( [0] => new value [1] => new value [2] => new value [3] => egg )

說明:在foreach中使用&引用後,當foreach結束後,$key和$val變數也都不會被自動釋放掉,但是此時$val和$arrcount($arr) - 1指向相同的記憶體地址。因此,此時修改$val的值也會改變了$arr[3]的值。

這種情況下很容易犯的錯誤就是像上面例子所示,在迴圈外面繼續使用被foreach引用的變數,這樣會使開發者得不到預期的資料。因此,為了避免這種情況的發生,應該在適當的位置釋放變數的引用。以上面的程式碼為例:

<?php 
    $arr = array('apple','banana','cat','dog');
    //在foreach中使用引用
    foreach($arr as $key => &$val)
    {
        $val = 'new value';
    }
    unset($val);

    echo $val;  //報錯,Notice: Undefined variable: val
    echo $key;  //輸出3

    $val = 'egg'; 
    print_r($arr);  //輸出Array ( [0] => new value [1] => new value [2] => new value [3] => new value ) 在foreach結束後unset $val,此時會釋放對$val的引用。因此改變$val不會對$arr造成影響。

這是最近在專案中遇到的坑和解決方案的總結,如果錯誤或更好地建議,歡迎指出。

原文地址:http://www.aintnot.com/2015/04/25/talk-about-a-hole-in-php-foreach-quote/