• foreach 與 reference 的雷


    前陣子公司定期技術研討會時,有人提出了一個問題。

    $arr = [1, 2, 3]; 
    
    foreach ($arr as &$a) {}
    foreach ($arr as $a) {}
    
    var_dump($arr); 

    考慮以上程式碼執行結果,試問陣列 $arr 在執行結束後的值會是如何?

    註:執行環境 PHP 7.1 without swoole

    結果:$arr 的值為 [1, 2, 2]

     

    緣由

    在 PHP 中,foreach 結束後,迴圈中的索引值(index)及內容(value)並不會被消滅。

    $a = [1, 2, 3]; 
    foreach ($a as $v) {}
    
    var_dump($v); // int(3)
    
    foreach ($a as $k => $value) {}
    
    var_dump($k, $value); // int(2), int(3)

    同理,foreach ($a as &$v) {} 時,在迴圈結束後 $v 值不會被消滅,其值仍是參考於(referenced by)陣列中的最後一個值,執行範例如下:

    $a = [1, 2, 3]; 
    foreach ($a as &$v) {}
    
    var_dump($a); 
    /*
    array(3) {
      [0]=>
      int(1)
      [1]=>
      int(2)
      [2]=>
      &int(3)
    }
    */

    如果在迴圈結束後變更 $v 值,則陣列中的最後一個值也會一併被變更。

     

    解決方法

    在使用 foreach ($a as &$v) {} 這類寫法後,應手動 unset($v) 以避免潛在問題發生。

    $a = [1, 2, 3];
    foreach ($a as &$v) {
        // do something... 
    }
    unset($v);

    http://php.net/manual/en/control-structures.foreach.php

    为了能够直接修改循环中的数组元素,在$ value之前 加上&。在这种情况下,该值将通过引用分配 

    <?php
    $arr = array(1, 2, 3, 4);
    foreach ($arr as &$value) {
        $value = $value * 2;
    }
    // $arr is now array(2, 4, 6, 8)
    unset($value); // break the reference with the last element
    ?>

    警告

    即使在foreach循环之后,$ value和最后一个数组元素的 引用仍然存在建议通过unset()销毁它否则您将遇到以下行为:

    <?php
    $arr = array(1, 2, 3, 4);
    foreach ($arr as &$value) {
        $value = $value * 2;
    }
    // $arr is now array(2, 4, 6, 8)
    
    // without an unset($value), $value is still a reference to the last item: $arr[3]
    
    foreach ($arr as $key => $value) {
        // $arr[3] will be updated with each value from $arr...
        echo "{$key} => {$value} ";
        print_r($arr);
    }
    // ...until ultimately the second-to-last value is copied onto the last value
    
    // output:
    // 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
    // 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
    // 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
    // 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
    ?>
  • 相关阅读:
    如何利用WGET覆写已存在的档案
    linux 脚本返回值
    ubuntu的配置网络
    非交互模式修改Ubuntu密码的命令
    [zz]python多进程编程
    [zz]linux修改密码出现Authentication token manipulation error的解决办法
    [zz]4.1.5 进程的处理器亲和性和vCPU的绑定
    vcpu
    非交互式调用交互式程序
    HDOJ_ACM_饭卡
  • 原文地址:https://www.cnblogs.com/yszr/p/10516397.html
Copyright © 2020-2023  润新知