Amp ⋅ Iterators

Iterators are the next level after promises. While promises resolve once and with one value, iterators allow a set of items to be consumed.

Iterator Consumption

Every iterator in Amp follows the Amp\Iterator interface.

namespace Amp;

interface Iterator {
    public function advance(): Promise;
    public function getCurrent();
}

advance() returns a Promise and its resolution value tells whether there’s an element to consume or not. If it resolves to true, getCurrent() can be used to consume the element at the current position, otherwise the iterator ended and there are no more values to consume. In case an exception happens, advance() returns a failed promise and getCurrent() throws the failure reason when called.

Simple Consumption Example

$iterator = foobar();

while (yield $iterator->advance()) {
    $element = $iterator->getCurrent();
    // do something with $element
}

Iterator Creation

Emitter

What Deferred is for promises, is Emitter for iterators. A library that returns an Iterator for asynchronous consumption of an iterable result creates an Amp\Emitter and returns the Iterator using iterate(). This ensures a consumer can only consume the iterator, but not emit values or complete the iterator.

emit()

emit() emits a new value to the Iterator, which can be consumed by a consumer. The emitted value is passed as first argument to emit(). emit() returns a Promise that can be waited on before emitting new values. This allow emitting values just as fast as the consumer can consume them.

complete()

complete() marks the Emitter / linked Iterator as complete. No further emits are allowed after completing an Emitter / Iterator.

Producer

Producer is a simplified form of Emitter that can be used when a single coroutine can emit all values.

Producer accepts a callable as first constructor parameter that gets run as a coroutine and passed an $emit callable that can be used to emit values just like the emit() method does in Emitter.

Example

$iterator = new Producer(function (callable $emit) {
    yield $emit(1);
    yield $emit(new Delayed(500, 2));
    yield $emit(3);
    yield $emit(4);
});

fromIterable

Iterators can also be created from ordinary PHP arrays or Traversable instances, which is mainly useful in tests, but might also be used for the same reasons as Success and Failure.

function fromIterable($iterable, int $delay = 0) { ... }

$delay allows adding a delay between each emission.