Download the PHP package sanmai/pipeline without Composer
On this page you can find all versions of the php package sanmai/pipeline. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Short Description General-purpose collections pipeline
All versions of pipeline with dependencies
Informations about the package pipeline
Pipeline makes dealing with
iterable types as easy as it can be, making it a perfect tool for bespoke data processing pipelines, hence the name. If you ever piped together several bash commands where one command uses output of another in succession, this library does just that but for PHP functions, generators, arrays, and iterators.
Pipeline comes with the most important yet basic building blocks. It boasts methods to map, filter, reduce, zip, and unpack data from arbitrary generators and from all kinds of standard iterators.
This rigorously tested library just works. Pipeline neither defines nor throws any exceptions.
composer require sanmai/pipeline
The latest version requires PHP 7.1 or above, including PHP 8.0.
There are earlier versions that work under PHP 5.6 and above, but they are not as feature complete.
API entry points
All entry points always return an instance of a standard pipeline.
||Takes an optional initial callback, where it must not require any arguments. Other than that, works just like an instance method below.||
||Takes any iterable, including arrays, initializes a standard pipeline with it.||
||Takes an array, initializes a standard pipeline with it.||
||Takes an iterable, and several more, merging them together.||
Instance methods in a nutshell
||Takes an optional callback that for each input value may return one or yield many. Also takes an initial generator, where it must not require any arguments. Provided no callback does nothing. Also available as a plain function.||
||Takes a callback that for each input value expected to return another single value. Unlike
||Takes a number of iterables, merging them together with the current sequence, if any.||
||Unpacks arrays into arguments for a callback. Flattens inputs if no callback provided.||
||Removes elements unless a callback returns true. Removes falsey values if no callback provided.||
||Reduces input values to a single value. Defaults to summation. Requires an initial value.||
||Returns an array with all values. Eagerly executed.||
||Can be provided with an optional initial iterator. Used in the
Pipeline is an iterator and can be used as any other iterable.
Pipeline can be used as an argument to
Countable. Be warned that operation of counting values is a terminal operation.
Pipeline is a final class. It comes with an interface to aid you with composition over inheritance.
In general, Pipeline instances are mutable, meaning every Pipeline-returning method returns the very same Pipeline instance. This gives us great flexibility on trusting someone or something to add processing stages to a Pipeline instance, while also avoiding non-obivius mistakes, raised from a need to strictly follow a fluid interface. E.g. if you add a processing stage, it stays there no matter if you capture the return value or not. This peculiarity could have been a thread-safety hazard in other circumstances, but under PHP this is not an issue.
Since most callback are lazily evaluated as more data coming in and out, you must consume the results with a plain
foreachor use a
reduce()to make sure processing happens.
Almost nothing will happen unless you use the results. That's the point of lazy evaluation after all!
That said, if a non-generator used to seed the pipeline, it will be executed eagerly.
In the above case the pipeline will store an array internally, with which the pipeline will operate eagerly whenever possible. Ergo, when in doubt, use a generator.
Keys for yielded values are being kept as is on a best effort basis, so one must take care when using
iterator_to_array()on a pipeline: values with duplicate keys will be discarded with only the last value for a given key being returned.
Safer would be to use provided
toArray()method. It will return all values regardless of keys used, making sure to discard all keys in the process.
This method also takes an optional argument to keep the keys.
The resulting pipeline is an iterator and should be assumed not rewindable, just like generators it uses.
Although there are some cases where a pipeline can be rewinded and reused just like a regular array, a user should make no assumptions about this behavior as it is not a part of the API compatibility guarantees.
IteratorAggregatewhich is not the same as
Iterator. Where the latter needed, the pipeline can be wrapped with an
- Iterating over a pipeline all over again results in undefined behavior. Best to avoid doing this.
Classes and interfaces: overview
\Pipeline\Standardis the main user-facing class for the pipeline with sane defaults for most methods.
\Pipeline\Principalis an abstract class you may want to extend if you're not satisfied with defaults from the class above. E.g.
getIterator()can have different error handling.
StandardPipelinedefines all public methods from the standard pipeline, most useful for mocking in tests.
This library is built to last. There's not a single place where an exception is thrown. Never mind any asserts whatsoever.
Takes an instance of
Traversable or none. In the latter case the pipeline must be primed by passing an initial generator to the
map method. This method is not part to any interface, as per LSP.
Takes a processing stage in a form of a generator function or a plain mapping function. Provided no callback does nothing.
Can also take an initial generator, where it must not require any arguments.
An extra variant of
map which unpacks arrays into arguments for a callback.
map() you would use:
unpack() these things are done behind the scene for you:
You can have all kinds of standard type checks with ease too.
With no callback, the default callback for
unpack() will flatten inputs:
Works similarly to map, but does not have a special treatment for generators. Think of
For this example, where
map() would have filled the pipeline with a series of payments,
cast() will add a generator for each customer.
Sequence-joins several iterables together, forming a feed with elements side by side:
With iterators with unequal number of elements, missing elements are left as nulls.
Takes a filter callback not unlike that of
Standard pipeline has a default callback with the same effect as in
array_filter: it'll remove all falsy values.
Takes a reducing callback not unlike that of
array_reduce with two arguments for the value of the previous iteration and for the current item.
As a second argument it can take an inital value.
Standard pipeline has a default callback that sums all values.
Returns an array with all values from a pipeline. All array keys are ignored to make sure every single value is returned.
If in the example about one would use
iterator_to_array($result) they would get just
A method to conform to the
Traversable interface. In case of unprimed
\Pipeline\Standard it'll return an empty array iterator, essentially a no-op pipeline. Therefore this should work without errors:
This allows to skip type checks for return values if one has no results to return: instead of
null it is safe to return an unprimed pipeline.
Contributions to documentation and test cases are welcome. Bug reports are welcome too.
API is expected to stay as simple as it is, though.
About collection pipelines in general
About collection pipelines programming pattern by Martin Fowler.
What else is out there:
Iteration primitives using generators provide functions like array_map and such, but returning lazy generators. You'll need quite some glue to accomplish the same thing Pipeline does out of box.
League\Pipeline is good for single values only. Similar name, but very different purpose. Not supposed to work with sequences of values. Each stage may return only one value.
Illuminate\Support\Collection a fluent wrapper for working with arrays of data. Can only work with arrays, also immutable, which is kind of expected for an array-only wrapper.
Knapsack is a close call. Can take a Traversable as an input, has lazy evaluation. But can't have multiple values produced from a single input. Has lots of utility functions for those who need them: they're out of scope for this project.
Primitives for functional programming in PHP by Lars Strojny et al. is supposed to complement currently exisiting PHP functions, which it does, although it is subject to some of the same shortcomings as are
array_filter. No method chaining.
Chain provides a consistent and chainable way to work with arrays in PHP, although for arrays only. No lazy evaluation.
Simple pipes with PHP generators by Hugh Grigg. Rationale and explanation for an exceptionally close concept. Probably one can use this library as a drop-in replacement, short of different method names.
If you're familiar with Java, package java.util.stream offers an implementation of the same concept.
- Submit a PR to add yours.