(底部的示例!)

我们刚刚将后端升级到PHP7,此后,我们在代码中发现了一个与ArrayObject相关的错误。

该代码仅循环遍历一个Object的副本( native ArrayObject类型)。 foreach按值迭代。

该代码的目的是过滤一些不需要的值。在示例中,如果迭代值为“两个”或“三个”,则将其取消设置。我已经尝试过使用迭代器代替复制的值,并且没有迭代器。

结果:

-迭代器

  • PHP 5.6:按预期工作,返回值是不包含值“两个”和“三个”的数组
  • PHP 7:仅删除“两个”,并且似乎未评估值为“三”的项目(请参见循环内的回显,它不显示“三”)

  • -没有迭代器
  • PHP 5.6:收到通知,但按预期运行,返回值是不包含值“two”和“3”的数组
  • PHP 7:仅删除“两个”,并且似乎未评估值为“三”的项目(请参见循环内的回显,它不显示“三”)

  • 第一个循环=> $ key = 0,$ value =“one”//继续

    第二个循环=> $ key = 1,$ value =“second”//未设置

    第三循环=> $ key = 3,$ value =“four”//WTF? $ key = 2在哪里,$ value =“三”?

    所以我不知道发生了什么。我们的临时解决方案是遍历原始对象,并从副本中取消设置。有谁知道PHP核心(或ArrayObject/ArrayIterator)中的哪个更改会导致此变化?我对此进行了搜索,但是某些人在foreach中遇到了这个问题,因为该项目是通过引用进行迭代的。

    如果在PHP 5.6和7之间切换,则行为会更改。

    Example 1 (with iterator)
    $elements = new ArrayObject();
    $elements->append('one');
    $elements->append('two');
    $elements->append('three');
    $elements->append('four');
    
    print_r($elements);
    
    $clone = clone $elements;
    $it = $clone->getIterator();
    
    echo "\n------\n";
    foreach ($it as $key => $value) {
        echo $key."\t=>\t".$value."\n";
        if ($value == 'two' || $value == 'three') {
            $it->offsetUnset($key);
        }
    }
    echo "\n------\n";
    print_r($clone);
    

    Example 2 (without iterator)
    $elements = new ArrayObject();
    $elements->append('one');
    $elements->append('two');
    $elements->append('three');
    $elements->append('four');
    
    print_r($elements);
    
    $clone = clone $elements;
    
    echo "\n------\n";
    foreach ($clone as $key => $value) {
        echo $key."\t=>\t".$value."\n";
        if ($value == 'two' || $value == 'three') {
            $clone->offsetUnset($key);
        }
    }
    echo "\n------\n";
    print_r($clone);
    

    非常感谢!

    最佳答案

    据我了解,这是不明智的做法,
    在遍历数组时修改数组,正确的方法是使用array_filter

    由于您具有ArrayObject,因此一种解决方案是将其导出到数组,使用array_filter对其进行过滤,然后从过滤后的数组中创建一个新的ArrayObject

    另请参见:Filter ArrayObject (PHP)

    可能是由于php7对循环的处理方式不同而引起的。如此处所述:php5中的http://php.net/manual/en/control-structures.foreach.php与php7相比,foreach使用内部数组指针。

    关于php - 在ArrayObject中循环和取消设置时,foreach中的意外行为。一项被忽略,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40087458/

    10-11 22:23
    查看更多