php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81330 Generator does not allow return null with implicit yield
Submitted: 2021-08-04 11:29 UTC Modified: 2021-08-04 12:44 UTC
From: greedy dot ivan at gmail dot com Assigned: cmb (profile)
Status: Not a bug Package: *General Issues
PHP Version: 8.0.9 OS: All
Private report: No CVE-ID: None
 [2021-08-04 11:29 UTC] greedy dot ivan at gmail dot com
Description:
------------
If there is not explicit yield instruction in Generator, it will throw TypeError message when null is returned.

https://3v4l.org/EpIjA

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

function foo($flag = false): \Generator
{
    if ($flag) {
        return null;
    }
    
    yield from [1, 2];
}

function bar($flag = false): \Generator
{
    if ($flag) {
        return null;
    }
    
    return internal();
}

function internal(): \Generator
{
    yield from [1, 2];
}

foreach (foo() as $v){}
foreach (foo(true) as $v){}
foreach (bar() as $v){}
foreach (bar(true) as $v){}

Expected result:
----------------
No error 

Actual result:
--------------
Fatal error: Uncaught TypeError: bar(): Return value must be of type Generator, null returned in /in/EpIjA:15

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-08-04 11:39 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2021-08-04 11:39 UTC] cmb@php.net
If the generator function does not necessarily return a Generator,
you shouldn't declare it as such.
 [2021-08-04 11:49 UTC] greedy dot ivan at gmail dot com
It doesn't throw error on all other cases.

It will throw Type error only in case, when yield is implicit and null is returned.
 [2021-08-04 11:57 UTC] cmb@php.net
That type check is done at runtime, not compile time.  And there
is no implicit yield.
 [2021-08-04 12:25 UTC] greedy dot ivan at gmail dot com
There are three options here.

1. There is an yield operator inside a function. Parser gets it and allow to return null as a valid end for generator.

2. There is no yield operator inside a function but there is a return instruction that returns Generator. This line works fine.

3. The same as 2, but we have a line, that returns null. It will throws Error, because Parser doesn't allow return an empty Generator such way. It doesn't get, that function return Generator at all, because there is no yield operation inside function itself.

So, we must use some tricks to return empty Generator in this case, or use `yield from func()` instead for `return func()`.
 [2021-08-04 12:44 UTC] cmb@php.net
Actually, the point is that bar() is not a generator function at
all, because there is no yield.  You probably want something like
<https://3v4l.org/hRSNS>.
 [2021-08-04 13:04 UTC] greedy dot ivan at gmail dot com
I understand it.

This is a refactoring issue. You have a return type hint. You have an yield inside a function. And when you move yield instruction somewhere you get a runtime type error because you generator-function now use return instead of yield. And you get this error not on a primary case.

I agree that it is not a bug. One more difficulties with generators in php.
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Wed May 18 10:05:45 2022 UTC