prelude / prelude-iterators
A Collection of Iterators
Requires
- php: >=5.3
- prelude/prelude: *
This package is auto-updated.
Last update: 2018-12-14 20:50:52 UTC
README
This a small collection of Iterators that covers cases not provided by php's defaults.
Why?
By using Iterators we can defer the execution of heavy operation until needed; which means faster execution. If you even find yourself working with code like this:
function getItems() { $result = array(); foreach(callDatabase() as $item) { $result[] = doSomething($item); // eager example -- DONT DO THIS } return $result; }
This library provides Iterators that allows to handle such scenario as this:
function getItems() { return new Map(callDatabase(), function ($item) { return doSomething($item); // lazy creation as needed }); }
Install
composer.json:
{ "require": { "prelude/prelude-iterators": "*" } }
See packagist for branch information.
Iterators:
Generator(Closure $yield)
This iterator will call the $yield
function when new elements are needed.
It will continue generating new elements until some falsy
value is returned.
$counter = new Generator(function() { static $n = 0; return ++$n; }); foreach ($counter as $number) { echo $number; // prints 1, 2, 3, 4, ... forever }
Unlike PHP Generators (php >= 5.5) this Iterator allows to rewind itself and start over.
Records(PDOStatement $stmt[, $fetchStyle])
This iterator will take care of efficiently fetching records, as they are needed, from a PDOStatement. Once all records are fetched, the iterator will close the PDOStatement; so there's no need for to do so.
$records = new Records( $pdo->query("SELECT * FROM blablah...") ); foreach ($records as $i => $record) { // do something with $record }
PDOStatement
provides differents ways to fetch objects. Records
iterators were designed to stay out of your way!
// set the statement to fetch records as User's instances $stmt->setFetchMode(PDO::FETCH_CLASS, Foo\Bar\User::CLASS); $records = new Records($stmt); // .. shortcut style $records = new Records($stmt, PDO::FETCH_CLASS, Foo\Bar\User::CLASS); foreach ($records as $user) { $user instanceof Foo\Bar\User; }
Records
iterators use Generators
under the hood, so they are really cheap to create; plus you can rewind them multiple times.
Memoize(Iterator $iterator)
Some iterators handle expensive operations. The Memoize
will make sure the results are generated only once.
$iterator = new Memoize(new ExpensiveIterator()); foreach ($iterator as $item) { // call ExpensiveIterator, and memoize each element } foreach ($iterator as $item) { // iterator over the memoized elements }
Where(Traversable $elements, Closure $predicate)
Filter the elements by calling the $predicate
function.
$admins = new Where($users, function ($user) { return $user->isAdmin(); });
If you're using php >= 5.4 use php's SPL
CallabackFilterIterator
instead.
Map(Traversable $elements, Closure $transform)
Transform the elements by calling the $transform
function on each element.
$names = new Map($users, function ($user) { return $user->getName(); });
Cycle(Traversable $elements)
This iterator will cycle indefinitely. Once the last element is reach, it will start over
$cycle = new Cycle(new \ArrayIterator(array(1))); forEach ($cycle as $i) { echo $i; // always prints 1 --> infinite loop }
Query(Iterator $iterator)
The Query provides a chainable interface for creating Iterators. All the operations can be made using regular Iterators, but this class allows working with them in a very natural way:
$names = Query::from($db->getUsers()) ->where(function($user) { return $user->isAdmin(); // pick only admins }) ->select(function($user) { return $user->getName(); // return their names }) ->limit(5); // return the first 5 foreach ($names as $name) { echo $name; }
The Query::from
method was crafted to accept both array
and Traversable
instances.
Feedback?
Please give it a try, and let me know!