php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72692 Bad behaviour of AppendIterator with Empty Generator
Submitted: 2016-07-28 05:09 UTC Modified: 2016-07-28 23:59 UTC
Votes:13
Avg. Score:4.4 ± 0.7
Reproduced:11 of 13 (84.6%)
Same Version:1 (9.1%)
Same OS:2 (18.2%)
From: pierrick@php.net Assigned:
Status: Open Package: SPL related
PHP Version: 5.6.24 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: pierrick@php.net
New email:
PHP Version: OS:

 

 [2016-07-28 05:09 UTC] pierrick@php.net
Description:
------------
When giving an new empty generator, AppendIterator will directly throw an Exception "Cannot traverse an already closed generator" even if the given generator is new.

Test script:
---------------
<?php

function createEmptyGen() { if(false) { yield 1; } }
$gen = createEmptyGen();

$ai = new AppendIterator();
$ai->append($gen);
var_dump(iterator_to_array($gen));


Expected result:
----------------
array(0) {
}


Actual result:
--------------
Fatal error: Uncaught Exception: Cannot traverse an already closed generator in /home/pierrick/php-src/github/foo.php:14
Stack trace:
#0 /home/pierrick/php-src/github/foo.php(14): iterator_to_array(Object(Generator))
#1 {main}
  thrown in /home/pierrick/php-src/github/foo.php on line 14


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-07-28 23:59 UTC] nikic@php.net
Related: Bug #71436
 [2019-09-17 15:03 UTC] f dot bosch at genkgo dot nl
I hit this bug too today, still valid in PHP7.4. See https://3v4l.org/R4AH3. For others who hit this bug: use a closure and yield from as alternative.

function createEmptyGen1() { if(false) { yield 1; } }
function createEmptyGen2() { if(false) { yield 2; } }

$ai = (function () {
    yield from createEmptyGen1();
    yield from createEmptyGen2();
})();

foreach ($ai as $_);
 [2021-06-01 13:11 UTC] enumag at gmail dot com
What's even worse is that this bug is quite hidden - if the empty generator is NOT the first iterator in the AppendIterator then everything works fine. It only breaks if the empty generator is first.

----

Test script:

<?php

function createGenerator(array $array): Generator
{
    yield from $array;
}

// Example 1 (works)

$iterator = new AppendIterator();
$iterator->append(createGenerator([1]));
$iterator->append(createGenerator([2]));
$iterator->append(createGenerator([]));
$iterator->append(createGenerator([3]));

foreach ($iterator as $value) {
    echo $value;
}

// Example 1 (fails)

$iterator = new AppendIterator();
$iterator->append(createGenerator([])); // <-- this line is new
$iterator->append(createGenerator([1]));
$iterator->append(createGenerator([2]));
$iterator->append(createGenerator([]));
$iterator->append(createGenerator([3]));

foreach ($iterator as $value) {
    echo $value;
}

----

Expected result:

123456

----

Actual result:

123
Fatal error: Uncaught Exception: Cannot traverse an already closed generator in /in/jRMa7:29
Stack trace:
#0 /in/jRMa7(29): AppendIterator->rewind()
#1 {main}
  thrown in /in/jRMa7 on line 29

Process exited with code 255.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 17:01:58 2024 UTC