php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #49104 AppendIterator::append($iterator) calls $iterator->rewind() with no reason
Submitted: 2009-07-29 22:54 UTC Modified: 2017-10-24 07:26 UTC
Votes:14
Avg. Score:4.4 ± 0.8
Reproduced:14 of 14 (100.0%)
Same Version:5 (35.7%)
Same OS:5 (35.7%)
From: seva dot lapsha at gmail dot com Assigned:
Status: Open Package: SPL related
PHP Version: 5.3.0 OS: *
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: seva dot lapsha at gmail dot com
New email:
PHP Version: OS:

 

 [2009-07-29 22:54 UTC] 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.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-07-29 22:57 UTC] 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:)
 [2011-03-23 18:32 UTC] 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
 [2013-09-09 08:49 UTC] hanskrentel at yahoo dot de
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.
 [2017-10-24 07:26 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: colder +Assigned To:
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Dec 11 14:02:33 2024 UTC