在ArrayObject中循环和取消设置时foreach中出现意外行为.项目被忽略

Dan*_*eto 9 php arrays foreach arrayobject php-7

(底部的例子!!!)

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

代码只是循环遍历Object的一个副本(类型为native ArrayObject).foreach按值迭代.

代码的目的是过滤一些您不需要的值.在示例中,如果迭代值为"2"或"3",则取消设置.我已经尝试使用迭代器而不是复制的值而没有迭代器.

结果:

- 迭代器

  • PHP 5.6:按预期工作,返回值是没有值"two"和"three"的数组
  • PHP 7:它只删除"两个"并且似乎没有评估值为"3"的项目(请参阅循环内的回显,它不打印"三")

- 没有迭代器

  • PHP 5.6:收到通知但按预期工作,返回值是没有值"two"和"three"的数组
  • PHP 7:它只删除"两个"并且似乎没有评估值为"3"的项目(请参阅循环内的回显,它不打印"三")

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

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

第三循环=> $ key = 3,$ value ="四"// WTF?哪里是$ key = 2,$ value ="三"????

所以我无法理解发生了什么.我们的时间解决方案是迭代原始对象并从副本中取消设置.有谁知道PHP核心(或ArrayObject/ArrayIterator)中的哪个更改?我有搜索它,但有些人有foreach这个问题,迭代的项目是参考.

如果在PHP 5.6和7之间切换,则行为会发生变化.

示例1(使用迭代器)

$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);
Run Code Online (Sandbox Code Playgroud)

例2(没有迭代器)

$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);
Run Code Online (Sandbox Code Playgroud)

非常感谢!

ore*_*iss 1

根据我的理解,在循环遍历数组时修改数组被认为是一种不好的做法,正确的方法是使用array_filter.

由于您有一个ArrayObject,一种解决方案是将其导出到一个数组,使用过滤它并从过滤后的数组array_filter创建一个新的。ArrayObject

另请参阅此处:过滤器 ArrayObject (PHP)

这种行为可能是由于 php7 中循环的处理方式不同所致。正如这里提到的: http: //php.net/manual/en/control-structs.foreach.phpforeach与 php7 相比,php5 中使用内部数组指针。