Edit report at https://bugs.php.net/bug.php?id=49104&edit=1
ID: 49104
Comment by: hanskrentel at yahoo dot de
Reported by: seva dot lapsha at gmail dot com
Summary: AppendIterator::append($iterator) calls
$iterator->rewind() with no reason
Status: Assigned
Type: Bug
Package: SPL related
Operating System: *
PHP Version: 5.3.0
Assigned To: colder
Block user comment: N
Private report: N
New Comment:
AppendIterator just takes care that the internal iterator state is at a
validated position of at least one iterator. This perhaps is not necessary at
all, but it *might* be needed to take care of internal iterator states as PHP
shares a lot of code across iterators (as this ticket didn't get much traction
nor feedback from core developers, I'd say in summary nobody wants to fiddle
with that). In the end AppendIterator is still an IteratorIterator and those
have this internal state:
Compare: Why must I rewind IteratorIterator -
http://stackoverflow.com/q/2458955/367456
In code: http://lxr.php.net/xref/PHP_5_4/ext/spl/spl_iterators.c#3347
If rewind on appending is an issue - and despite / in contrast to what has been
outlined as workaround already - if those safety checks PHP does are not
wanted,
you can take care your own by adding the iterators directly to the internal
collection of iterators:
<?php
$i1 = new ArrayIterator1(array(1, 2, 3));
$i2 = new ArrayIterator1(array(4, 5, 6));
$append = new AppendIterator();
/* @var $i ArrayIterator */
$i = $append->getArrayIterator();
$i->append($i1);
$i->append($i2);
Some notes:
- You can append anything here, no type-check is enforced. However everything
not a Traversable will crash the script on iteration when reached (e.g. exit
code -1073741819). This has the benefit that unlike ArrayIterator::append() you
*can* add Traversable (e.g. IteratorAggregate) and not only Iterator. This also
works for Traversable only classes like DatePeriod.
- This still does work while iterating (as it does for
AppendIterator::append()).
- ArrayAccess can be used, too: $i[] = $i1;
I hope this helps someone running into the issue in PHP user land.
Previous Comments:
------------------------------------------------------------------------
[2011-03-23 18:32:46] demjan at kaluzki dot de
The rewind is invoked only on the first appended (not empty) inner-iterator.
workaround:
$workaround = new
ArrayIterator(array('delete_me_after_all_append_calls_are_done'));
$a = new ArrayIterator(array('a', 'b'));
$b = new ArrayIterator(array('c', 'd'));
$append = new AppendIterator();
$append->append($workaround); // invokes implicit:
// $workaround->rewind();
// $workaround->valid();
// $workaround->current();
// $workaround->key();
// $workaround->rewind();
$append->append($a);
$append->append($b);
unset($workaround[0]); // no further append calls are allowed,
// otherwise it seems to hang up in infinite loop
------------------------------------------------------------------------
[2009-07-29 22:57:40] seva dot lapsha at gmail dot com
Line 6:
x This causes append to happen twice:
should be read as
* This causes rewind to happen twice:)
------------------------------------------------------------------------
[2009-07-29 22:54:19] seva dot lapsha at gmail dot com
Description:
------------
AppendIterator::append($iterator) calls $iterator->rewind() with no reason.
This causes append to happen twice:
1) when $iterator appended;
2) when $iterator starts iterating.
Reproduce code:
---------------
<?php
class ArrayIterator1 extends ArrayIterator {
function rewind() {
echo ".";
parent::rewind();
}
}
$i1 = new ArrayIterator1(array(1, 2, 3));
$i2 = new ArrayIterator1(array(4, 5, 6));
$i = new AppendIterator();
$i->append($i1);
$i->append($i2);
foreach ($i as $n) {
echo $n;
}
?>
Expected result:
----------------
.123.456
rewind() of each append()ed iterator should be called on demand when iterating
and not when append()ing.
Actual result:
--------------
..123.456
On each append() each append()ed iterator's rewind is called with no need.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=49104&edit=1