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

Php 在ArrayObject中循环和取消设置时foreach中出现意外行为。项目被忽略,php,arrays,foreach,php-7,arrayobject,Php,Arrays,Foreach,Php 7,Arrayobject,(底部的示例!!!) 我们刚刚将后端升级到PHP7,之后,我们在与ArrayObject相关的代码中发现了一个bug 代码只是在对象的副本上循环(类型为native ArrayObject)。foreach按值进行迭代 代码的目的是过滤一些不需要的值。在本例中,如果迭代值为“2”或“3”,则取消设置它。我尝试过使用迭代器而不是复制的值,并且没有使用迭代器 结果: -迭代器 PHP5.6:按预期工作,返回的值是没有值“2”和“3”的数组 PHP7:它只删除了“2”,并且似乎没有对值为“3”的项进

底部的示例!!!

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

代码只是在对象的副本上循环(类型为native ArrayObject)。foreach按值进行迭代

代码的目的是过滤一些不需要的值。在本例中,如果迭代值为“2”或“3”,则取消设置它。我尝试过使用迭代器而不是复制的值,并且没有使用迭代器

结果:

-迭代器
  • PHP5.6:按预期工作,返回的值是没有值“2”和“3”的数组
  • PHP7:它只删除了“2”,并且似乎没有对值为“3”的项进行求值(参见循环中的echo,它没有打印“3”)
-无迭代器
  • PHP5.6:得到一个通知,但工作正常,返回的值是没有值“2”和“3”的数组
  • PHP7:它只删除了“2”,并且似乎没有对值为“3”的项进行求值(参见循环中的echo,它没有打印“3”)
第一个循环=>$key=0,$value=“一”//继续

第二个循环=>$key=1,$value=“第二个”//unset

第三个循环=>$key=3,$value=“四”//WTF?其中$key=2,$value=“三”

所以我无法理解发生了什么。我们的临时解决方案是迭代原始对象并从副本中取消设置。有人知道PHP核心(或ArrayObject/ArrayIterator)中的哪些更改导致了这种情况吗?我已经搜索过了,但是有些人对foreach有这个问题,因为该项是通过引用迭代的

如果在PHP5.6和PHP7之间切换,行为会发生变化


非常感谢

据我所知,这被认为是一种不好的做法 在循环遍历数组时修改数组,正确的方法是使用
array\u filter

由于您有一个
ArrayObject
,一个解决方案是将其导出到数组中,使用
array\u filter
对其进行过滤,然后从过滤后的数组中创建一个新的
ArrayObject

另见此处:


这种行为可能是由于在php7中循环的处理方式不同。如本文所述:在php5
foreach
中,与php7相比,foreach使用内部数组指针。

请将实际代码粘贴为文本,而不是链接或图片。ArrayObject在这两种情况下都使用迭代器,如果取消设置偏移量,则迭代器中的position超过一个元素,并跳过下一个元素。如果您执行
$it->seek($key-1)
$it->offsetUnset($key)之后
那么它应该可以工作是的@MarekJanoud,它可以工作,但是它没有解释PHP5.6和PHP7之间的任何变化。这是一个已知的问题:不要拖延时间,这是一个棘手的问题。实际上我不确定,我说的是
$it->seek($key-1)没有帮助,抱歉,奇怪的行为。只要按照答案去做,一切都会好起来的OK@orestiss这可能是一个不好的做法,也可能是一个很好的建议,但是……主要的问题是,在PHP5.6中,它可以按照预期工作,而在PHP7中,没有。核心中的任何东西都发生了变化。我想这可能是关于(ArrayIterator的)next()的任何事情……如果你阅读最后一段,然后是包含完整解释的链接,那么这个问题在这个答案中得到了完整的回答。使用指针是为了不直接修改数组。您必须恢复到PHP5.6或以不同的方式重写循环,因为这是新预期的行为。
$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);
$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);