dajoha / php-iter
A bunch of functional-like iterators.
Requires
- php: >=8.1
Requires (Dev)
- phpstan/phpstan: ^1.12
- phpunit/phpunit: ^9
This package is not auto-updated.
Last update: 2025-06-17 11:00:52 UTC
README
Provides rust-like iterators for php.
Warning: This package is just a proof of concept, but should not be used in a production environment.
Features
- Lazy iterators;
- Chainable methods;
- Carefully designed, coherent API.
Pros
- Greatly improves code readability.
Cons
- Has a big runtime cost compared to a classical
for
loop (something like 15x slower!). But for small loops (less than 1000 elements), this runtime cost may be acceptable.
Installing
In your php project, run
composer require dajoha/php-iter
Basic usage
$numbers = [1, 30, 50, 123, 3, 5, 100, 3780];
$output = iter($numbers) // Convert the input array to an `IteratorInterface`
->filter(fn($n) => $n > 100) // Keep only numbers which are > 100
->map(fn($n) => "Number $n") // Map each remaining number to a formatted string
->join("\n"); // Reduce the iterator to a single string
echo "$output\n";
Output:
Number 123
Number 3780
More examples
See the directory /examples
in this repository for more usage examples.
API overview
The API offers a central interface: IteratorInterface
, which extends the native php Iterator
but
gives many more abilities to it.
There are two kinds of native classes which implement IteratorInterface
:
- Generators, which create an
IteratorInterface
from any input source (like simple arrays, or anything which implements native phpIterator
); - Modifiers, which transform a given
IteratorInterface
into another one.
Once an iterator has been created, it has to be "consumed" in a way or another, in order to give a
useful result (the most basic way is to call the native php method Iterator::next()
). In this
doc, this is called reducing an iterator. Some methods are provided in IteratorInterface
, in
order to handle very common reducing operations, like converting to an array (toValues()
), making
the sum of numbers (sum()
)... All these reducing methods are implemented in AbstractIterator
,
which every class in this package is based on.
Generators
Generators are IteratorInterface
s which can be constructed from any kind of input parameters.
For example, a generator could be a class which provides:
- A simple list of concrete values like
[78, 'foo', 'bar']
; - A list of famous musicians, by giving a certain time period as an input;
- The infinite list of primary numbers.
Modifiers
A modifier is an IteratorInterface
which takes an iterable as first input, and transforms the
result of the inner iterable when it is consumed.
Each native modifier class has a dedicated method in IteratorInterface
which allows to chain it
with other modifiers (or with a final reducer method).
For example:
- the
Map
modifier iterator transforms each value of its inner iterator. - the
Filter
modifier iterator only provides values which fill the given condition.
Reducers
Reducers are methods (typically implemented inside AbstractIterator
) which transform the given
iterator to a final value, by consuming elements of their iterator (not necessarily all the
elements, even if it's often the case).
For example, AbstractIterator::sum()
is a reducer method which consumes all the iterator elements
(by assuming they are numbers), and which returns the whole sum of those elements.
Summary of the native generators
The Iter
generator
The Iter
class is the most basic generator: it simply wraps the given iterable, which can be
either:
- A php array (by using internally
ArrayIterator
); - A php
Iterator
; - A php
IteratorAggregate
(by trying to retrieve the inner iterator); - A php callable (by wrapping it into a
Func
generator).
The iter()
global function
The Iter
generator is so commonly used, that a global function is provided in order to wrap its
constructor: iter()
.
Other native generators
Class | Description |
---|---|
Alternate | Alternate values of multiple iterators |
AsciiChars | Iterate over bytes in a string |
Cartesian | Cartesian product between several iterators |
Chain | Chains multiple child iterators together |
Chars | Iterate over utf-8 chars in a string |
Counter | Generate a custom suite of numbers |
Forever | Repeat a value forever |
Func | Return the updated result of a function's call, forever |
Interleave | Interleave values of two iterators |
Letters | Iterate over well-known sequences of characters |
Zip | Iterate over multiple iterators simultaneously |
Summary of the IteratorInterface
methods
Modifier methods
Modifier methods are methods which transform the actual iterator to another one. Here is a list of the native modifier methods:
alternate() // Alternate values of multiple iterators.
apply() // Wrap the iterator into a custom iterator.
cartesian() // Performs the cartesian product between current and child iterators.
chain() // Chain the iterator with other iterators.
chunks() // Create an iterator over chunks of N elements.
filter() // Filter the values of the iterator by using a callable.
filterKeys() // Filter the keys of the iterator by using a callable.
flatten() // Flatten the iterator, by assuming that each element is iterable itself.
interleave() // Interleaves the values of the iterator with another iterator.
limit() // Limit the number of elements of the iterator.
loop() // Loop over the iterator a certain number of times.
mapKeys() // Map the keys of the iterator by using a callable.
mapKeyValues() // Map the keys and values of the iterator by using a callable.
map() // Map the values of the iterator by using a callable.
run() // Just run the given callable on each item.
skip() // Skip the given number of elements at the start of the iterator.
slice() // A combination of skip() and limit().
zip() // Iterate over multiple iterators simultaneously.
Consuming/reducing methods
Once the wanted iterator has been created, then one "reducer" method can be called. These methodS
will consume the iterator (partially or totally), so in order to reuse the iterator, the native
Iterator
method rewind()
has to be called first.
Here is a list of the reducing methods:
isFound() // Advance the iterator until the given predicate returns `true`.
find() // Advance the iterator until the given predicate returns `true`.
first() // Return the first value of the iterator.
last() // Return the last value of the iterator. Consume the iterator entirely.
nth() // Return the given Nth value of the iterator. Consume the iterator until this item is reached.
reduce() // Reduce the iterator to a single value.
all() // Check if all the iterator values fill the requirement of the given predicate.
any() // heck if at least one of the iterator values fills the requirement of the given predicate.
count() // Return the number of items of the iterator. Consume the iterator entirely.
min() // Return the minimum value of the iterator.
max() // Return the minimum value of the iterator.
sum() // Return the sum of the values of the iterator.
average() // Return the average of the values of the iterator.
join() // Join all the values of the iterator into a single string.
toValues() // Return an array of all the values of the iterator.
toArray() // Return an array of all the values of the iterator.
consume() // Consume all the iterator (like toValues(), but don't return anything).
Development
Running the test suite
$ composer create-project dajoha/php-iter
$ cd php-iter
$ vendor/bin/phpunit
Running phpstan
$ composer create-project dajoha/php-iter
$ cd php-iter
$ vendor/bin/phpstan analyze -v