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

时间:2016-10-17 13:17:54

标签: php arrays foreach php-7 arrayobject

底部的例子!!!

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

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

代码的目的是过滤一些您不需要的值。在这个例子中,如果迭代值是"两个"或者"三个",取消它。我已经尝试使用迭代器而不是复制的值而没有迭代器。

结果:

- 迭代器

  • PHP 5.6:按预期工作,返回的值是没有值的数组" 2"和"三"
  • PHP 7:它只删除"两个"并且似乎有价值的物品"三"没有评估(参见循环中的回声,它没有打印"三")

- 没有迭代器

  • PHP 5.6:收到通知但按预期工作,返回的值是没有值的数组" 2"和"三"
  • PHP 7:它只删除"两个"并且似乎有价值的物品"三"没有评估(参见循环中的回声,它没有打印"三")

First loop => $ 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);

非常感谢!

1 个答案:

答案 0 :(得分:0)

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

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

另见:Filter ArrayObject (PHP)

可能这种行为是由于在php7中循环的处理方式不同。如上所述:php5 foreach中的http://php.net/manual/en/control-structures.foreach.php使用内部数组指针而不是php7。