Skip to content

Commit 22aa726

Browse files
committed
Updated Readme.
1 parent f0a2e3c commit 22aa726

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

README.md

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88

99
## Why fluent iterators?
1010

11-
Flow provides a fluent interface to assemble chains of iterators and other data processing operations. Instead of
12-
collecting values into arrays and managing nested `foreach` loops manually, you compose small, intention-revealing
13-
operations that stream data from one step to the next. The expressive syntax makes it **easy and enjoyable** to build
14-
sophisticated processing pipelines while keeping memory usage low and the intent of each transformation crystal clear.
11+
PHP has a rich set of iterators and other data processing tools - like the iterators in the Standard PHP Library (SPL) - but they are often not used to their full potential, as they are cumbersome to use and require a lot of boilerplate code.
12+
13+
Flow provides a fluent interface to assemble chains of iterators and other data processing operations, making it easy to write complex data processing pipelines in a concise and readable way.
14+
15+
Instead of collecting values into arrays and managing nested `foreach` loops manually, you compose small, intention-revealing operations that stream data from one step to the next.
16+
17+
The expressive syntax makes it **easy and enjoyable** to build sophisticated processing pipelines while keeping **memory usage low** and the intent of each transformation crystal clear.
1518

1619
### Example: data crunching in one expression
1720

@@ -31,15 +34,23 @@ $topCustomers = Flow::from($orders)
3134
->all();
3235
```
3336

34-
The same workflow using temporary arrays and for-loops would be longer, harder to read and would duplicate values in
35-
memory multiple times. A Flow pipeline keeps the computation streaming, lets you re-use SPL iterators seamlessly and
36-
makes experimentation as simple as inserting or removing a step.
37+
The same workflow using temporary arrays and for-loops would be longer, harder to read and would duplicate values in memory multiple times.
38+
39+
A Flow pipeline keeps the computation streaming, lets you re-use SPL iterators seamlessly and makes experimentation as simple as inserting or removing a step.
3740

3841
## Flow is **not** the usual Collection-style utility library
3942

40-
Typical Collection-like classes use arrays underneath. But `Flow`, even though it also uses a chainable fluent interface, is both an `Iterator` and a `Traversable` (therefore with native PHP support), and works perfectly with **Generators** and **SPL iterators**, with no arrays underneath. **Each iteration step only requires one value to be in memory (it can be generated on the fly), and the data is streamed through the pipeline**.
43+
Although many libraries exist for implementing collections (e.g. Laravel Collections), Flow is different, even though, on the surface, it seems similar, as it also provides a chainable fluent interface.
44+
45+
Typical Collection-like classes use arrays underneath. But Flow (most of the time) **does not**.
46+
47+
48+
Flow is both an `Iterator` and a `Traversable` (therefore with native PHP support), and works perfectly with **Generators**, **SPL iterators** and `foreach` loops.
49+
50+
Each iteration step only requires **one value** to be in memory (and it can be generated on the fly), and the data is streamed through the pipeline, with **no intermediate storage** and **without needless data copying**.
4151

42-
Since Flow implements both `Iterator` and `Traversable`, you can use a Flow object anywhere you would use a `Traversable` or `Iterator`. For example, you can use `foreach` directly over a Flow object:
52+
You can use a Flow object anywhere an `Iterator` or `Traversable` interface is expected.
53+
For example, you can use `foreach` directly over a Flow object:
4354

4455
```php
4556
foreach (Flow::from([1, 2, 3]) as $value) {
@@ -63,6 +74,21 @@ function processItems(Traversable $items) {
6374
processItems(Flow::from($data)->map($transformer));
6475
```
6576

77+
You can even generate values on the fly:
78+
79+
```php
80+
$values = Flow::from(function () {
81+
for ($i = 1; $i <= 3; $i++) {
82+
yield $i;
83+
}
84+
});
85+
```
86+
In this example, **the values are generated only when they are read, not when the flow is created**, which is a **major difference** from traditional collections.
87+
88+
This also means that if the iteration is not fully consumed, some values may not be generated at all. This lazy evaluation is particularly important when value generation is computationally expensive, as it avoids unnecessary computation.
89+
90+
Additionally, when processing very large datasets, Flow maintains minimal memory usage by processing values one at a time as they stream through the pipeline, rather than loading the entire dataset into memory.
91+
6692
## Fluent operations reference
6793

6894
### Creating flows
@@ -73,7 +99,7 @@ processItems(Flow::from($data)->map($transformer));
7399
| `Flow::from($src)` | Convenience constructor that forwards to `new Flow($src)`.
74100
| `Flow::range($from, $to, $step = 1)` | Streams a numeric range (inclusive) without allocating intermediate arrays.
75101
| `Flow::sequence($list)` | Concatenates a list of iterables and iterates them sequentially.
76-
| `Flow::combine($inputs, array $fields = null, int $flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_ASSOC)` | Zips multiple iterables together, yielding keyed tuples of values.
102+
| `Flow::combine($inputs, array $fields = null, int $flags = MultipleIterator::MIT_NEED_ANY \| MultipleIterator::MIT_KEYS_ASSOC)` | Zips multiple iterables together, yielding keyed tuples of values.
77103
| `Flow::void()` | Produces an empty flow, handy as a neutral element when composing.
78104

79105
### Combining and extending sequences
@@ -149,7 +175,7 @@ processItems(Flow::from($data)->map($transformer));
149175

150176
| Method | Description |
151177
| --- | --- |
152-
| `FilesystemFlow::from(string $path, int $flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS)` | Streams directory entries with full control over SPL flags.
178+
| `FilesystemFlow::from(string $path, int $flags = FilesystemIterator::KEY_AS_PATHNAME \| FilesystemIterator::CURRENT_AS_FILEINFO \| FilesystemIterator::SKIP_DOTS)` | Streams directory entries with full control over SPL flags.
153179
| `FilesystemFlow::glob(string $pattern, int $flags = 0)` | Iterates filesystem matches similar to `glob()` but lazily.
154180
| `FilesystemFlow::recursiveFrom(string $path, int $flags = FilesystemIterator::KEY_AS_PATHNAME \| FilesystemIterator::CURRENT_AS_FILEINFO \| FilesystemIterator::SKIP_DOTS, int $mode = RecursiveIteratorIterator::SELF_FIRST)` | Builds a recursive traversal using `RecursiveIteratorIterator` and a configurable recursion mode.
155181
| `FilesystemFlow::recursiveGlob(string $rootDir, string $pattern, int $flags = 0)` | Performs recursive glob searches, yielding `SplFileInfo` objects or paths according to flags.
@@ -190,8 +216,7 @@ The `globals.php` helpers make it effortless to adopt Flow throughout an applica
190216

191217
## Notes
192218

193-
Some operations (such as `reverse()` or `sort()`) need to materialize the stream into an array before continuing. The
194-
library only buffers data when absolutely necessary and automatically returns to streaming mode afterwards.
219+
Some operations (such as `reverse()` or `sort()`) need to materialize the stream into an array before continuing. The library only buffers data when absolutely necessary and automatically returns to streaming mode afterwards.
195220

196221
## License
197222

0 commit comments

Comments
 (0)