php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79511 Return is silently ignored with yield even if yield is never reached
Submitted: 2020-04-23 00:38 UTC Modified: 2020-04-23 09:24 UTC
From: michael dot vorisek at email dot cz Assigned: cmb (profile)
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.4.5 OS: any
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: michael dot vorisek at email dot cz
New email:
PHP Version: OS:

 

 [2020-04-23 00:38 UTC] michael dot vorisek at email dot cz
Description:
------------
See test script

Test script:
---------------
function x(): iterable {
    yield 'a';
    
    return ['b']; // silently ignored!
}

function y(): iterable {
    if (false) {
        yield 'c';
    }
    
    return ['d']; // not returned at all - yield above needs to be commented out even if the condition is never matched!
}


foreach (x() as $v) {echo $v."\n";}
echo "\n";
foreach (y() as $v) {echo $v."\n";}

Expected result:
----------------
a
b

d

Actual result:
--------------
a



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-04-23 07:16 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2020-04-23 07:16 UTC] cmb@php.net
No, the `return` is not ignored; it just has special semantics in
generator functions; see <https://3v4l.org/rCAX4> and
<https://github.com/php/php-langspec/blob/master/spec/14-classes.md#class-generator>.
 [2020-04-23 08:20 UTC] michael dot vorisek at email dot cz
But the 2nd example does not call yield at all - if (false) {} pattern is used a lot to comment code to keep it refactorable - why is this allowed and where is this behaviour defined?
 [2020-04-23 08:25 UTC] nikic@php.net
Any function containing yield is a generator and follows generator semantics. Whether the yield actually gets executed does not matter.

Please, this is generators 101.
 [2020-04-23 08:41 UTC] michael dot vorisek at email dot cz
This should then be - like return - not allowed, shouldn't?

$u = fn() => yield 5;
echo $u();
 [2020-04-23 08:50 UTC] nikic@php.net
Why would that be disallowed? It's equivalent to

function() {
    return yield 5;
}

which is not terribly useful, but perfectly legal code. It yields one value, accepts one value and specifies the accepted value as the coroutine return value.
 [2020-04-23 09:12 UTC] michael dot vorisek at email dot cz
Ok, just example how to mix non-generator and generator return.

class Cl {
    public function __get($name) {
        if ($name === 'gen') {
            return (fn() => yield 'a')(); // return generator
        } else {
            return ['b']; // return array
        }
    }
}

$cl = new Cl();
var_dump($cl->gen);
var_dump(iterator_to_array($cl->gen));
var_dump($cl->not_gen);
 [2020-04-23 09:24 UTC] cmb@php.net
In this case, Cl::__get() is a normal function, not a generator
function.  The anonymous function inside of Cl::__get() is a
generator function, though.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon May 06 19:01:32 2024 UTC