You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SplFixedArray can be used in nested 'foreach' loops
Because SplFixedArray is an Iterator, and stores its own iteration state, it cannot be
used in nested 'foreach' loops. If you try, the inner loop will overwrite the iteration
position of the outer loop, so that the outer loop 'thinks' it is finished after the inner
loop finishes.
To illustrate:
$spl = SplFixedArray::fromArray([0, 1]);
foreach ($spl as $a) {
foreach ($spl as $b) {
echo "$a $b";
}
}
Only prints two lines:
0 0
0 1
Interestingly, though SplFixedArray has methods like ::current(), ::next(), etc., these
are not used by the 'foreach' loop. Rather, an instance of '_spl_fixedarray_it' is created
internally and used to track the iteration state.
Therefore, if the current iteration position is stored in '_spl_fixedarray_it', the nested
'foreach' loops will not interfere with each other in this way.
However, the problem is that ::current(), ::next(), etc. are still part of the SplFixedArray
interface and users may expect them to 'work' in a 'foreach' loop. For ::next() and ::rewind(),
there is nothing we can do, since the SplFixedArray instance does not keep any reference to
the _spl_fixedarray_it structures being used by the 'foreach' loops. However, we can still keep
::valid(), ::current(), and ::key() working by keeping a current iteration position in each
SplFixedArray instance and updating it at the same time as we update the _spl_fixedarray_it.
Although, they still break in cases like this:
foreach ($spl as $a) {
foreach ($spl as $b) {
// do something
}
$spl->key(); // will NOT return iteration position of outer loop
}
Overall, this fix stinks and it may be better to bite the bullet and convert SplFixedArray
to IteratorAggregate.
0 commit comments