php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77587 Inconsistent behaviour when returning generators
Submitted: 2019-02-08 12:03 UTC Modified: 2019-02-08 12:07 UTC
From: adamnicholson10 at gmail dot com Assigned:
Status: Not a bug Package: *General Issues
PHP Version: Irrelevant OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: adamnicholson10 at gmail dot com
New email:
PHP Version: OS:

 

 [2019-02-08 12:03 UTC] adamnicholson10 at gmail dot com
Description:
------------
There appears to be inconsistent behaviour when returning generators.

Given the function `foo()` returns a generator, when you consume that generator in a new function which also returns a generator, you would expect `return foo()` to have the same behaviour as looping over the values of `foo()` and performing a `yield` on each value; however this doesn't appear to be the case if the function you are consuming `foo()` contains other yield statements.

It looks like PHP is getting confused by having both `yield` statements, and `return $generator` statements, in the same function body.

This appears to affect all PHP versions tested which support generators

POC (code below): https://3v4l.org/e86mK

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

function generator() {
    foreach ([1, 2, 3, 4, 5] as $i) {
        yield $i;
    }
}

function A(): \Generator {
    return generator();
}

function B(): \Generator {
    if (false) {
        yield 7;
        return;
    }
    return generator();
}

function C(): \Generator {
    if (false) {
        yield 7;
        return;
    }
    foreach (generator() as $i) {
        yield $i;
    }
}

echo "-A\n";
foreach (A() as $i) {
    echo "{$i}\n";
}

echo "-B\n";
foreach (B() as $i) {
    echo "{$i}\n";
}

echo "-C\n";
foreach (C() as $i) {
    echo "{$i}\n";
}

echo "Done\n";


Expected result:
----------------
-A
1
2
3
4
5
-B
1
2
3
4
5
-C
1
2
3
4
5
Done

Actual result:
--------------
-A
1
2
3
4
5
-B
-C
1
2
3
4
5
Done

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-02-08 12:07 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2019-02-08 12:07 UTC] nikic@php.net
return foo() is just that: You are returning a generator object.

What you are looking for is "yield from foo()". See also http://php.net/manual/en/language.generators.syntax.php#control-structures.yield.from
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon May 06 08:01:33 2024 UTC