Simplest PHP Generator Example
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!
NIce writeup, thanks! Didn’t know about generators. That’s too bad the average PHP update rate is so slow on most hosting
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]
When is php 5.5 being released? I’d love to start using yield in production code today!
Officially due for release in July
Thanks, Lorna Jane! Your posts are always so clearly & concisely written
>>> 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?