If your generator works by setting up another generator and then iterating through it with "yield from", without yielding anything of its own, you could just return the other generator and save yourself a whole layer of delegation.
<?php
function first_generator(int $a, int $b): Generator
{
for($i = $a; $i < $b; ++$i)
yield $i * $i;
}
function second_generator(int $a, int $b): Generator
{
if($a > $b) [$a, $b] = [$b, $a];
yield from first_generator(2 * $a, 2 * $b);
}
foreach(second_generator(4, 2) as $j) echo "$j\n";
?>
Once it starts iterating, the only thing second_generator is doing is delegating to first_generator and passing along what it gets back unchanged. second_generator can be made into an ordinary function that simply returns a suitably-constructed instance of first_generator to be iterated over directly. It's literally just a matter of replacing "yield from" with "return":
<?php
function first_generator(int $a, int $b): Generator
{
for($i = $a; $i < $b; ++$i)
yield $i * $i;
}
function second_generator(int $a, int $b): Generator
{
if($a > $b) [$a, $b] = [$b, $a];
return first_generator(2 * $a, 2 * $b);
}
foreach(second_generator(4, 2) as $j) echo "$j\n";
?>
Skipping that extra level of iteration.