ehough/generators
, (*1)
Easily backport generators to PHP 5.3 and 5.4., (*2)
Why?
Generators were introduced to PHP in version 5.5, but sadly 60% of all PHP web servers still run PHP 5.4 and lower. This library makes it (relatively) easy to backport code that relies on generators for use on legacy systems., (*3)
This library will be retired once PHP 5.5+ levels reach 85%. If you don't need to backport code to PHP 5.3 or 5.4, you don't need this library., (*4)
Quick Start
Say you need to use the following code on PHP 5.3:, (*5)
$generator = function ($values) {
print "Let's get started\n";
foreach ($values as $key => $value) {
yield $key => $value;
}
print "Nothing more to do\n";
};
$items = array('foo' => 'bar', 'some' => 'thing');
foreach ($generator($items) as $k => $v) {
print "The generator gave us $k => $v\n";
}
The above code results in:, (*6)
Let's get started
The generator gave us foo => bar
The generator gave us some => thing
Nothing more to do
Since the code above uses generators, it won't run on PHP 5.4 or lower. This library provides you with the AbstractGenerator
class, which requires you to implement resume($position)
. $position
is incremented each time the generator resumes execution, and you can use the position to determine which part of the generator to run. So the above generator could be rewritten as:, (*7)
use Hough\Generators\AbstractGenerator
class MyGenerator extends \Hough\Promise\AbstractGenerator
{
private $keys;
private $values;
public function __construct(array $items)
{
$this->keys = array_keys($items);
$this->values = array_values($items);
}
protected function resume($position)
{
// first execution
if ($position === 0) {
print "Let's get started\n";
}
// still inside the for loop
if ($position < count($this->values)) {
// return an array of two items: the first is the yielded key, the second is the yielded value
return array(
$this->keys[$position],
$this->values[$position]
);
}
// we must be done with the for loop, so print our last statement and return null to signal we're done
print "Nothing more to do\n";
return null;
}
}
$items = array('foo' => 'bar', 'some' => 'thing');
foreach (new MyGenerator($items) as $k => $v) {
print "The generator gave us $k => $v\n";
}
The above code results in:, (*8)
Let's get started
The generator gave us foo => bar
The generator gave us some => thing
Nothing more to do
The code is not nearly as clean and simple, but any generator can be rewritten using this library., (*9)
Yielding Keys and Values
You have three choices for what you return from resume($position)
:, (*10)
- If you return null, you are signaling that there are no more statements inside the generator. The generator will be considered to be closed at this point.
- If you return an array with two values, the first element is interpreted to be the yielded key and the second value is the yielded value.
- If you return an array with one value, it is interpreted to be a yielded value, and
$position
will be used as the key.
Accessing Sent Values
You can access the last value sent in from the caller with getLastValueSentIn()
. This might be null
., (*11)
Handling Exceptions
By default, if an exception is thrown into the generator (via throw(\Exception $e)
) it will be rethrown back to the calling context. If you'd like to "catch" these exceptions, you can override onExceptionThrownIn(\Exception $e)
and swallow or otherwise handle the exception., (*12)