(底部的示例!)
我们刚刚将后端升级到PHP7,此后,我们在代码中发现了一个与ArrayObject相关的错误。
该代码仅循环遍历一个Object的副本( native ArrayObject类型)。 foreach按值迭代。
该代码的目的是过滤一些不需要的值。在示例中,如果迭代值为“两个”或“三个”,则将其取消设置。我已经尝试过使用迭代器代替复制的值,并且没有迭代器。
结果:
-迭代器
-没有迭代器
第一个循环=> $ 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/