Skip to content
Advertisement

How to pass in an empty generator parameter?

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])
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement