Simplest PHP Generator Example

I really like the generators feature that's arriving in PHP 5.5, and since we're now into release candidate releases, it's actually not that far away. I've been speaking on this topic and I thought I'd share my trivially simple code example from my slides.

Writing a Generator

The generators use the yield keyword to feed values out as they are iterated over. In code, they really look a lot like a function (or method):

<?php
function getValues() {
    // totally trivial example
    yield "Apple";
    yield "Ball";
    yield "Cat";
}

The main difference is that this "function" will retain its state and yield the next value when it is used again.

Using a Generator

It's not obvious from the calling code that a generator is in use - and that's a feature IMO. Here's an example that uses the generator declared above:

<?php
$stuff = getValues();

foreach($stuff as $thing) {
    echo $thing . "\n";
}


From this, you might assume that getValues() returns an iterator or array. I can imagine refactoring applications that absolutely do expect either of those to use generators instead, so that's intentional! If you do var_dump($stuff), however, you'll see an object of type Generator.

Each time the foreach tries to fetch the next item from $stuff, the getValues() generator gets called, and runs until a yield statement causes a value to be emitted.

When To Use Generators

There's nothing in these examples that makes a generator a better choice than, say, returning an array, so why are generators even useful? For the most part, they will be great for either formulaic or very large datasets. If you wanted to perform some task on all prime numbers up to ten digits long, you could certainly generate a list and iterate over it. However, that list could be quite large, and the generator could calculate and supply the next value on an as-needed basis.

The other use is for data sets which are large in comparison to the size of the memory available to PHP. A generator could fetch data in a loop, or read incrementally from a stream, and only have that one piece of data hanging around in PHP's memory at any one time.

Looking Forward to Generators

Generators are just one more in a long string of understated features coming in to the newer versions of PHP, but it's one that will make your data-heavy applications run light and quick - I can't thank the PHP core team enough for bringing us this feature!

6 thoughts on “Simplest PHP Generator Example

  1. NIce writeup, thanks! Didn't know about generators. That's too bad the average PHP update rate is so slow on most hosting

  2. Slightly more complex example, generating fibonacci sequence values with a count and offset:

    [code]
    function fibonacci($count, $offset=0) {
    --$offset;

    $prev = 0;
    $current = 1;

    if ($offset <= 0) {
    --$count;
    yield $prev;
    } else {
    for ($i = 0; $i < $offset; ++$i) {
    $next = $prev + $current;
    $prev = $current;
    $current = $next;
    }
    }

    for ($i = 0; $i $value) {
    echo $i , ' -> ' , $value, PHP_EOL;
    }

    foreach (fibonacci(10,10) as $i => $value) {
    echo $i , ' -> ' , $value, PHP_EOL;
    }

    foreach (fibonacci(10,20) as $i => $value) {
    echo $i , ' -> ' , $value, PHP_EOL;
    }
    [/code]

  3. >>> A generator could read incrementally from a stream, and only have that one piece of data hanging around in PHP's memory at any one time.

    What's the difference between reading data from a stream in chunks and "incrementally" using generator?

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>