foreach循环中current()的意外行为

这个问题在这里已经有了答案:

  • PHP'foreach'如何实际工作? 7个答案

  • 为什么它以B开头?

    由于foreach (可靠地)在循环体开始前提前数组指针。 另请参阅FE_RESET操作码。

    $list = array("A", "B", "C","D");
    foreach ($list as $var) {
        break;
    }
    var_dump(current($list));
    

    输出:

    B
    

    这可能与ZEND_OP_DATA伪操作码的工作方式有关(没有真正记录)。

    为什么current()一直给出相同的值?

    在循环开始之前, foreach为你正在循环的数组创建一个内部引用。 一旦进入循环,每当数组变量被修改或通过引用传递时,通过复制数组结构(而不​​是元素)来将内部引用从变量中解除关联。 该复制值保留了数组指针(之前已通过循环初始化进行修改)。

    这种行为还会带来更具破坏性的unset()操作:

    $list = array('A', 'B', 'C', 'D');
    foreach ($list as $key => $val) {
      echo $val;
      unset($list[1], $list[2], $list[3]);
    }
    echo "n", print_r($list, true), "n";
    

    输出:

    ABCD
    Array
    (
        [0] => A
    )
    

    将循环变量传递给一个函数

    这是另一个有趣的场景:

    $list = array('A', 'B', 'C', 'D');
    function itm($arr) 
    {
        return current($arr);
    }
    
    foreach ($list as $item) {
        print itm($list);
    }
    var_dump(current($list));
    

    输出:

    BCDA
    bool(false)
    

    这一次,数组是通过值传递的,因此它的数组结构被复制(而不是元素)到函数的$arr参数中。 与前面的示例不同,循环的内部引用和$list符号之间没有分离,因为复制发生在函数作用域中。

    最后的"A"呢?

    这是迄今为止最神秘行为foreach ,只能在这些情况下见证。 在最后一次循环迭代中,数组指针看似倒回到第一个项目; 看起来是因为在循环结束时它显然指向元素的末尾(正如你可以从输出的最后一行看到的那样)。

    这可能与在foreach结尾执行的SWITCH_FREE操作码有关。

    那么为什么在一个函数中放置foreach使它与众不同呢?

    请注意以下代码:

    function item2($arr) 
    {
        foreach ($arr as $var) {
            print(current($arr));
        }
        var_dump(current($arr));
    }
    $list = array("A","B","C","D");
    item2($list);
    

    输出:

    AAAA
    string(1) "A"
    

    在这种情况下, foreach的内部引用会使用数组的副本进行初始化(因为它的refcount> 1),因此会立即从$arr符号中解除关联。

    它会变得更糟吗?

    当然! 当你开始使用引用或者在同一个变量上嵌套多个foreach循环时,你甚至可能会产生令人怀疑的结果。

    那么我怎样才能获得一致的结果呢?

    使用Iterators或不要依靠在foreach操作期间引用数组变量来获取一致的值。


    FROM PHP.net

    current()函数只是返回当前内部指针指向的数组元素的值。 它不会以任何方式移动指针

    然后:使用next()

    $list = array("A", "B", "C","D");
    foreach ($list as $var) {
        print(current($list));
        next($list);
    }
    

    注:第一个元素将不会被打印,因为foreach将指针移动到数组的第二个元素:)

    这个例子将解释完整的行为:

    $list = array("A", "B", "C","D");
    foreach ($list as $var) {
       if(!isset($a)) reset($list); $a = 'isset';
       print(current($list));
       next($list);
    }
    

    输出是ABCD

    还请注意:

    As foreach relies on the internal array pointer changing it within the loop 
    may lead to unexpected behavior.
    

    的foreach


    编辑:我想分享我的新混乱发现!

    例1:

    $list = array("A", "B", "C","D");
    $list_copy = $list;
    foreach ($list as $key => $val) {
      current($list_copy);
      echo current($list);
      //next($list);
    }
    

    输出:AAAA

    例2:

    $list = array("A", "B", "C","D");
    $list_copy = $list;
    foreach ($list as $key => $val) {
      current($list_copy);
      echo current($list);
      next($list);
    }
    

    输出:ABCD

    当在foreach中调用current()函数时,即使对于另一个数组,它也会影响foreach行为...

    示例3:

    $list = array("A", "B", "C","D");
    
    $refcopy = &$list;
    
    foreach ($list as $key => $val) {
      if(!isset($a)) { $a = 'isset'; reset($list); }
      echo current($list);
      next($list);
    }
    

    输出:ACD(WOW! B缺失)

    例如:4

    $list = array("A", "B", "C","D");
    
    $refcopy = &$list;
    
    foreach ($list as $key => $val) {
      echo current($list);
      next($list);
    }
    

    输出:BCD

    无法确定在foreach循环内会发生什么!


    那么,我不知道这是为什么,但我怀疑它可能与如何评估/处理任务有关。 为了好玩,我尝试了这一点,并导致另一个incorrect行为:

    $arr = array('A', 'B', 'C', 'D');
    function itm($val) {
        return current($val);
    }
    
    foreach ($arr as $item) {
        print itm($arr);
    }
    

    结果:BCDA

    所以我的猜测是,这里发生的事情是函数调用迫使评估电流以正确的方式发生。 此外,我得到BCDA而不是ABCD的原因可能是因为内部指针首先增加(指向B),然后在en中重新指向A点。

    在PHP文档中可能值得注意这一行:

    请注意,作业将原始变量复制到新变量(按值分配),因此对其中一个的更改不会影响另一个。 如果您需要在紧密循环内复制类似大数组的东西,这也可能具有相关性。

    我想这不算是一个答案,但我喜欢你的问题,并希望贡献一点。

    链接地址: http://www.djcxy.com/p/53023.html

    上一篇: Unexpected behaviour of current() in a foreach loop

    下一篇: PHP foreach inside loop on array that added inside the loop