( examples below! )
we just upgraded our server to PHP7 and after that we found an error in our code related to ArrayObject.
The code simply iterates over a copy of the object (type native ArrayObject). The foreach identifier iterates by value.
The purpose of the code is to filter out some values that you do not need. In the example, if the iterated value is two or three, disable it. I tried this using an iterator instead of the copied value and without an iterator.
Results:
- Iterator
- PHP 5.6: works as expected, the return value is an array with no two or three
- PHP 7: it only removes “two” and it seems that an element with a value of “three” is not evaluated (see the echo inside the loop, it does not print “three”)
- No iterator
- PHP 5.6: receives a notification, but works as expected, the return value is an array with no two or three
- PHP 7: it only removes “two” and it seems that an element with a value of “three” is not evaluated (see the echo inside the loop, it does not print “three”)
First loop => $ key = 0, $ value = "one" // continue
Second loop => $ key = 1, $ value = "second" // unset
Third loop => $ key = 3, $ value = "four" // WTF? where $ key = 2, $ value = "three" ????
Therefore, I cannot understand what is happening. Our temporary solution is to iterate over the original object and not use it. Does anyone know what changes in the PHP core (or ArrayObject / ArrayIterator) do this? I have a search on this, but some people have this problem with foreach if the element was repeated by reference.
If you switch between PHP 5.6 and 7, the behavior changes.
Example 1 (with an 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 an 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);
Many thanks!
arrays php foreach php-7 arrayobject
Daniel Nieto
source share