Bug #77515 [Opn->Dup]: A generator is closed by making a call to Generator::valid
Edit report at https://bugs.php.net/bug.php?id=77515&edit=1
ID: 77515
Updated by: nikic@php.net
Reported by: knyjoh at gmail dot com
Summary: A generator is closed by making a call to
Generator::valid
-Status: Open
+Status: Duplicate
Type: Bug
Package: *General Issues
PHP Version: 7.3.1
Block user comment: N
Private report: N
New Comment:
Marking this as a duplicate of bug #75819, which is about the empty case specifically, where we
arguably shouldn't throw due to the "at first yield" exception.
Previous Comments:
------------------------------------------------------------------------
[2020-03-08 20:50:08] nawarian at gmail dot com
That's a tricky one. I think this is actually the intended behaviour.
The Generator::valid() will check if the *current* value is not null. In order to fetch
Generator::current() it will have to init the generator function: this means, it will execute the
Generator function until it finds the first yielded value.
The following snippet might get us some more clue:
function gen() {
echo 1;
yield 2;
echo 3;
if (false) {
yield 4;
}
}
$it = gen();
$it->valid(); // true
// --> Output: 1
$it->current(); // 2 (yielded value)
// No extra output
$it->valid();
// No extra output (current value is 1, so it is still valid)
$it->next();
// --> Output: 3
// No further yield statements found
$it->valid(); // false
In your particular example, the yield statement is never accessible, so calling $it->valid() will
run through the whole function, making this generator invalid right away.
I don't see a better solution for this, though. I think the behaviour is correct.
------------------------------------------------------------------------
[2019-01-24 12:57:40] knyjoh at gmail dot com
Description:
------------
A generator is closed by making a call to Generator::valid
It is not the expected behavior that a call to valid() will actually change a state. If it is
considered a correct behavior it should be documented.
Note that the same problem exists with the current() function.
In example 1 it is clear that when reaching the loop the generator is not closed, because the loop
does not fail. Traversing a closed generator is not allowed and would throw an exception, which
means that the generator must be open at this stage.
In example 2 however, when reaching the loop an exception is thrown "Cannot traverse an already
closed generator". The generator has therefore been closed by the call to valid().
Test script:
---------------
1. <?php
2.
3. function generator() {
4. if (false) {
5. yield 1; // Force generator
6. }
7. }
8.
9. // Example 1
10. $values = generator();
11. foreach ($values as $value) {} // This is ok
12.
13. // Example 2
14. $values = generator();
15. $values->valid();
16. foreach ($values as $value) {} // This is not ok
Actual result:
--------------
Fatal error: Uncaught Exception: Cannot traverse an already closed generator in /in/ab0KK:16
Stack trace:
#0 {main}
thrown in /in/ab0KK on line 16
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=77515&edit=1
Thread (3 messages)