0

I want to use some methods which use Generators as their return type and by-reference. However, the problem is that a method gets another method's return value, that is returned by-reference and is a Generator, and returns it by-reference. Plus, nearly all methods return a value after yielding one or more values.

Let's see in a code:

class YieldFromByReferenceTest
{
    public $data = [
        "Ubuntu",
        "CentOS",
        "Fedora"
    ];

    protected function &sampleGenerator(): \Generator
    {
        foreach ($this->data as $key => &$datum) {
            yield $key => $datum;
        }
        // This is just a sample return type
        return true;
    }

    public function &useGenerator(): \Generator
    {
        $generator = $this->sampleGenerator();

        // Return $generator?
    }
}

Firstly, yield from came in my mind. However, when I try to use it, it gives me the following error:

PHP Fatal error: Cannot use "yield from" inside a by-reference generator in ./test.php on line xx

That looks strange to me. I don't know why it does not work (as in my mind, it should work). So, my questions are:

  1. In this case, why yield from doesn't work as expected and an error is generated? Shouldn't it work?

  2. What are the alternative solutions?

Thank you!

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40

1 Answers1

0

I'm going to post two solutions (please consider replacing the following codes with the part: // Return $generator? in the code in the question), but I can't really answer my first question.

Yielding and Returning

One possible solution is to yield all values from sampleGenerator() and then return its return value:

// Please notice the &
foreach ($generator as $key => &$value) {
    yield $key => $value;
}
return $generator->getReturn();

It works perfectly, and prevents from errors, even if using nested generators or if a generator does not yield or return any values. However, in some cases, as for me, the code would become harder to read, because of using it a lot.

Returning the Generator Itself

Simply, you can return the returned generator:

return $generator;

At first glance, it looks simpler, but if you are working on some complicated pieces of code, then it becomes a bit complicated. Just keep in mind, unless you use a yield statement somewhere in the function, it returns a Generator instance, and it is not a generator function. Notwithstanding, just like what happened for me, your problem may be fixed by adding an empty yield (pay attention, it will be a generator):

return $generator;
yield;

Note: It may be obvious, but these are not always-work solutions. You should consider your own problem and then try to fix it; so, you may need both ways to get the jobs done!

Hope it helps!

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40