(examples at the bottom!!!)
we have just upgrade our backend to PHP7 and after that, we have found a bug in our code related to an ArrayObject.
The code just loops over a copy of an Object (type native ArrayObject). The foreach iterates by value.
The purpose of the code is to filter some values that you don't need. In the example, if the iterated value is "two" or "three", unset it. I have tried it using iterator instead of the copied value and without the iterator.
Results:
- Iterator
- PHP 5.6: works as expected, the returned value is the array without the values "two" and "three"
- PHP 7: it only removes "two" and seems that the item with value "three" is not evaluated (see echo inside the loop, it doesn't print "three")
- No Iterator
- PHP 5.6: gets a notice but works as expected, the returned value is the array without the values "two" and "three"
- PHP 7: it only removes "two" and seems that the item with value "three" is not evaluated (see echo inside the loop, it doesn't print "three")
First loop => $key = 0, $value = "one" // continue
Second loop => $key = 1, $value = "second" // unset
Third loop => $key = 3, $value = "four" // WTF? where is the $key = 2, $value = "three"????
So I cannot understand what's going on. Our temporal solution is to iterate over the original object and unset from the copy. Does anybody knows which change in the PHP core (or ArrayObject/ArrayIterator) makes this? I have search about it but some people has this problem with foreach were the item iterated is by reference.
If you switch between PHP 5.6 and 7, the behaviour changes.
$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);
Thanks so much!
$it->seek($key - 1);
after$it->offsetUnset($key);
then it should work – Spirochaetosis$it->seek($key - 1);
will not help, sorry, strange behaviour. Just follow answer and everything will be OK – Spirochaetosis