V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
WytheHuang
V2EX  ›  PHP

为什么这个代码在 PHP 7.0 和 PHP 5.6 得出结果不同?

  •  
  •   WytheHuang · Apr 18, 2018 · 4126 views
    This topic created in 2932 days ago, the information mentioned may be changed or developed.
    $arr = array(0,1,2,3,4,5);
    $ref = &$arr;
    foreach($arr as $value){
        $arr = array();
        echo $value;
    }
    

    在 PHP7.0 中, 输出 012345, 而在 PHP 5 中 输出 0. PHP7.0 提及到 foreach 改变的有三点.

    1. foreach 不再改变内部数组指针.
    2. foreach 通过值遍历时,操作的值为数组的副本
    3. foreach 通过引用遍历时,有更好的迭代特性

    看到第二点有点懵, 我看一些资料都说 PHP 5 在 foreach 是操作数组副本的, 那么官方手册写这句话有什么含义还是有所变化? 为何会导致 PHP7.0 和 PHP 5 的结果截然不同?

    8 replies    2018-04-19 10:43:13 +08:00
    carlclone
        1
    carlclone  
       Apr 18, 2018
    二、按照值进行循环的时候,foreach 是对该数组的拷贝操作

    foreach 按照值进行循环的时候(by-value),foreach 是对该数组的一个拷贝进行操作。这样在循环过程中对数组做的修改是不会影响循环行为的。

    $array = [0, 1, 2];
    $ref =& $array; // Necessary to trigger the old behavior
    foreach ($array as $val) {
    var_dump($val);
    unset($array[1]);
    }

    http://www.jb51.net/article/91331.htm 这里第二点 , 以前应该不是拷贝了
    WytheHuang
        2
    WytheHuang  
    OP
       Apr 18, 2018
    @carlclone 但是, PHP 5 以前不是拷贝的话, 那么下面这个代码应该跟 PHP 7 不一样
    ```
    $arr = array('a','b','c');
    foreach ($arr as $key=> $value) {
    $arr[] = 'd';
    print_r($arr);
    var_dump($key,$value);
    }
    ```
    然而输出其结果也是一样的.
    > 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"
    而且上面代码$ref = &$array 为什么会出现这样结果, 不是很明白.
    jfcherng
        3
    jfcherng  
       Apr 18, 2018
    2. foreach by-value operates on a copy of the array

    When used in the default by-value mode, foreach will now operate on a copy of the array being iterated rather than the array itself. This means that changes to the array made during iteration will not affect the values that are iterated.

    把完整的官方說明看完啊,不要只看標題
    WytheHuang
        4
    WytheHuang  
    OP
       Apr 19, 2018
    DukeAnn
        5
    DukeAnn  
       Apr 19, 2018
    PHP 7 你可以这么理解,`foreach` 把整个数组隐式的镜像了一份给自己用,所以无论你怎么修改原数组都不会影响到 `foreach` 镜像数据,但是你打出来你原始数组是已经被修改了的。

    ```php
    $arr = array(0,1,2,3,4,5);
    $ref = &$arr;
    foreach($arr as $key => $value){
    $arr = array();
    echo "foreach 镜像数据:" . $value;
    echo "\n";
    echo "原始数组:";
    var_dump($arr);
    }
    ```

    运行结果:
    foreach 镜像数据:0
    原始数组:array(0) {
    }
    foreach 镜像数据:1
    原始数组:array(0) {
    }
    foreach 镜像数据:2
    原始数组:array(0) {
    }
    foreach 镜像数据:3
    原始数组:array(0) {
    }
    foreach 镜像数据:4
    原始数组:array(0) {
    }
    foreach 镜像数据:5
    原始数组:array(0) {
    }
    WytheHuang
        6
    WytheHuang  
    OP
       Apr 19, 2018
    @DukeAnn PHP 7 这样可以理解, 而在 PHP 5 中的, 加了引用. 情况有所不同的, 实时随着数组改变的, 就是这一点让我觉得很郁闷.
    ```
    // PHP 输出: foreach 镜像数据:0 原始数组:array(0) { }
    $arr = array(0,1,2,3,4,5);
    $ref = &$arr;
    foreach($arr as $key => $value){
    $arr = array();
    echo "foreach 镜像数据:" . $value;
    echo "\n";
    echo "原始数组:";
    var_dump($arr);
    }
    ```
    DukeAnn
        7
    DukeAnn  
       Apr 19, 2018
    @WytheHuang 这个没看具体文档,但是根据当前输出的情况和最近看 Go 语言的遍历机制,我推测 php5 应该是只缓存了当前遍历这一次的 $value 和 $key,而且遍历会改变原始数组的内部指针位置从而拿到下一个需要遍历的键值对,进行镜像。所以在 foreach 内部将数组赋值为空,第二次遍历就凉了。
    DukeAnn
        8
    DukeAnn  
       Apr 19, 2018
    @WytheHuang 个人推测,具体的可以自己实践一下,或者查查文档。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1025 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 92ms · UTC 22:09 · PVG 06:09 · LAX 15:09 · JFK 18:09
    ♥ Do have faith in what you're doing.