You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pipeline is a PHP library that brings the power of streaming pipelines to your code. Inspired by the pipe operator (`|>`), typical in functional programming languages, Pipeline lets you chain a series of operations on your data concisely, clearly, and readably. This approach simplifies complex data transformations and makes your code more maintainable and easier to test.
7
+
Pipeline is a PHP library that brings the power of streaming pipelines to your code. Inspired by the pipe operator (`|>`), typical in functional programming languages, Pipeline lets you chain a series of operations on your data concisely, clearly, and readably. This approach simplifies complex data transformations and makes your code more maintainable and easier to test.
8
8
9
-
The pipeline uses lazy evaluation to optimize performance, especially for large datasets. This means operations are not executed immediately but deferred until the final result is needed. The pipeline is built as a chain of generator functions, processing data iteratively without loading the entire dataset into memory.
9
+
The pipeline uses lazy evaluation to optimize performance, especially for large datasets. This means operations are not executed immediately but deferred until the final result is needed. The pipeline is built as a chain of generator functions, processing data iteratively without loading the entire dataset into memory.
10
10
11
11
This means the actual computation is deferred until the final result is needed. This approach offers the benefits of reduced memory usage, making it suitable for handling massive datasets, improved performance by avoiding unnecessary computations, and efficiency for large datasets or even infinite sequences. For example, if you have an array with a million numbers and want to find the first five even numbers multiplied by 2, thanks to the lazy evaluation, it will only process the first few necessary numbers.
12
12
@@ -126,7 +126,7 @@ All entry points always return an instance of the pipeline.
126
126
|`unpack()`| Unpacks arrays into arguments for a callback. Flattens inputs if no callback provided. ||
127
127
|`chunk()`| Chunks the pipeline into arrays of specified length. |`array_chunk`|
128
128
|`filter()`| Removes elements unless a callback returns true. Removes falsey values if no callback provided. |`array_filter`, `Where`|
129
-
|`skipWhile()`| Skips elements while the predicate returns true, and keeps everything after the predicate return false just once. ||
129
+
|`skipWhile()`| Skips elements while the predicate returns true, and keeps everything after the predicate return false just once. ||
130
130
|`slice()`| Extracts a slice from the inputs. Keys are not discarded intentionally. Suppors negative values for both arguments. |`array_slice`|
131
131
|`fold()`| Reduces input values to a single value. Defaults to summation. Requires an initial value. |`array_reduce`, `Aggregate`, `Sum`|
132
132
|`reduce()`| Alias to `fold()` with a reversed order of arguments. |`array_reduce`|
@@ -143,7 +143,7 @@ All entry points always return an instance of the pipeline.
143
143
|`finalVariance()`| Computes final statistics for the sequence. ||
144
144
|`__construct()`| Can be provided with an optional initial iterator. Used in the `take()` function from above. ||
145
145
146
-
Pipeline is an iterator and can be used as any other iterable.
146
+
Pipeline is an iterator and can be used as any other iterable.
147
147
148
148
Pipeline can be used as an argument to `count()`. Implements `Countable`. Be warned that operation of counting values is [a terminal operation](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps).
149
149
@@ -161,7 +161,7 @@ In general, Pipeline instances are mutable, meaning every Pipeline-returning met
161
161
```
162
162
163
163
Almost nothing will happen unless you use the results. That's the point of lazy evaluation after all!
164
-
164
+
165
165
- That said, if a non-generator used to seed the pipeline, it will be executed eagerly.
166
166
167
167
```php
@@ -172,28 +172,28 @@ In general, Pipeline instances are mutable, meaning every Pipeline-returning met
172
172
})->filter();
173
173
```
174
174
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.*
175
-
175
+
176
176
```php
177
177
$pipeline->map(function () {
178
178
// will be executed only as needed, when needed
179
179
yield $this->veryExpensiveMethod();
180
180
})->filter();
181
-
```
181
+
```
182
182
183
183
- 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.
184
-
184
+
185
185
```php
186
-
$pipeline = \Pipeline\map(function () {
187
-
yield 'foo' => 'bar';
188
-
yield 'foo' => 'baz';
189
-
});
190
-
191
-
var_dump(iterator_to_array($pipeline));
192
-
/* ['foo' => 'baz'] */
186
+
$pipeline = \Pipeline\map(function () {
187
+
yield 'foo' => 'bar';
188
+
yield 'foo' => 'baz';
189
+
});
190
+
191
+
var_dump(iterator_to_array($pipeline));
192
+
/* ['foo' => 'baz'] */
193
193
```
194
-
194
+
195
195
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.
196
-
196
+
197
197
```php
198
198
var_dump($pipeline->toArray());
199
199
/* ['bar', 'baz'] */
@@ -202,20 +202,20 @@ In general, Pipeline instances are mutable, meaning every Pipeline-returning met
202
202
203
203
- The resulting pipeline is an iterator and should be assumed not rewindable, just like generators it uses.
204
204
205
-
```php
206
-
$pipeline = \Pipeline\map(function () {
207
-
yield 1;
208
-
});
209
-
210
-
$sum = $pipeline->reduce();
211
-
212
-
// Won't work the second time though
213
-
$pipeline->reduce();
214
-
// Exception: Cannot traverse an already closed generator
215
-
```
216
-
217
-
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.
218
-
205
+
```php
206
+
$pipeline = \Pipeline\map(function () {
207
+
yield 1;
208
+
});
209
+
210
+
$sum = $pipeline->reduce();
211
+
212
+
// Won't work the second time though
213
+
$pipeline->reduce();
214
+
// Exception: Cannot traverse an already closed generator
215
+
```
216
+
217
+
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.
218
+
219
219
- Pipeline implements `IteratorAggregate` which is not the same as `Iterator`. Where the latter needed, the pipeline can be wrapped with an `IteratorIterator`:
220
220
221
221
```php
@@ -235,7 +235,7 @@ This library is built to last. There's not a single place where an exception is
235
235
236
236
## `__construct()`
237
237
238
-
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.
238
+
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.
239
239
240
240
## `$pipeline->map()`
241
241
@@ -331,7 +331,7 @@ Sequence-joins several iterables together, forming a feed with elements side by
Contributions to documentation and test cases are welcome. Bug reports are welcome too.
487
+
Contributions to documentation and test cases are welcome. Bug reports are welcome too.
488
488
489
489
API is expected to stay as simple as it is, though.
490
490
491
491
# About collection pipelines in general
492
492
493
-
About [collection pipelines programming pattern](https://martinfowler.com/articles/collection-pipeline/) by Martin Fowler.
493
+
About [collection pipelines programming pattern](https://martinfowler.com/articles/collection-pipeline/) by Martin Fowler.
494
494
495
495
In a more general sense this library implements a subset of [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes) paradigm, as opposed to [Actor model](https://en.wikipedia.org/wiki/Actor_model).
496
496
@@ -503,7 +503,7 @@ What else is out there:
503
503
-[Knapsack](https://github.com/DusanKasan/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.
504
504
-[transducers.php](https://github.com/mtdowling/transducers.php) is worth a close look if you're already familiar transducers from Clojure. API is not very PHP-esque. Read as not super friendly. [Detailed write-up from the author.](http://mtdowling.com/blog/2014/12/04/transducers-php/)
505
505
-[Primitives for functional programming in PHP](https://github.com/lstrojny/functional-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_map` and `array_filter`. No method chaining.
506
-
-[Chain](https://github.com/cocur/chain) provides a consistent and chainable way to work with arrays in PHP, although for arrays only. No lazy evaluation.
506
+
-[Chain](https://github.com/cocur/chain) provides a consistent and chainable way to work with arrays in PHP, although for arrays only. No lazy evaluation.
507
507
-[Simple pipes with PHP generators](https://www.hughgrigg.com/posts/simple-pipes-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.
508
508
-[loophp's Collection](https://github.com/loophp/collection) looks like a viable alternative to this library, as far as processing of multi-gigabyte log files goes. [Supports fluent interface.](https://loophp-collection.readthedocs.io/en/stable/pages/usage.html) It takes the immutability as a first principle, even though PHP's generators are inherently mutable.
509
509
- If you're familiar with Java, [package java.util.stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) offers an implementation of the same concept.
0 commit comments