I have a method which takes a generator plus some additional parameters and returns a new generator:
function merge(Generator $carry, array $additional) { foreach ( $carry as $item ) { yield $item; } foreach ( $additional as $item ) { yield $item; } }
The usual use case for this function is similar to this:
function source() { for ( $i = 0; $i < 3; $i++ ) { yield $i; } } foreach ( merge(source(), [4, 5]) as $item ) { var_dump($item); }
But the problem is that sometimes I need to pass empty source to the merge
method. Ideally I would like to be able to do something like this:
merge(Generator::getEmpty(), [4, 5]);
Which is exactly how I would do in C# (there is a IEnumerable<T>.Empty
property). But I don’t see any kind of empty
generator in the manual.
I’ve managed to work around this (for now) by using this function:
function sourceEmpty() { if ( false ) { yield; } }
And this works. The code:
foreach ( merge(sourceEmpty(), [4, 5]) as $item ) { var_dump($item); }
correctly outputs:
int(4) int(5)
But this is obviously not an ideal solution. What would be the proper way of passing an empty generator to the merge
method?
Advertisement
Answer
I’ve found the solution:
Since Generator
extends Iterator
I can just change the method signature to this:
function merge(Iterator $carry, array $additional) { // ...
This is input covariance thus it would break backward compatibility, but only if someone did extend the merge
method. Any invocations will still work.
Now I can invoke the method with PHP’s native EmptyIterator
:
merge(new EmptyIterator, [4, 5]);
And the usual generator also works:
merge(source(), [4, 5])