PHPackages                             anarchitecture/pipe - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. anarchitecture/pipe

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

anarchitecture/pipe
===================

Unary callable helpers to leverage PHP 8.5 pipes

v0.4.6(1mo ago)63912[1 PRs](https://github.com/Anarchitecture/pipe/pulls)1MITPHPPHP ^8.5CI failing

Since Jan 6Pushed 1mo agoCompare

[ Source](https://github.com/Anarchitecture/pipe)[ Packagist](https://packagist.org/packages/anarchitecture/pipe)[ RSS](/packages/anarchitecture-pipe/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (38)Used By (1)

anarchitecture/pipe
===================

[](#anarchitecturepipe)

[![CI](https://github.com/Anarchitecture/pipe/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Anarchitecture/pipe/actions/workflows/ci.yml) [![Latest Version](https://camo.githubusercontent.com/3b37249dbe8668b5303ed1a9ed60e31392bf58e4b6b9f27bd2feb04abf973396/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616e6172636869746563747572652f70697065)](https://packagist.org/packages/anarchitecture/pipe) [![License](https://camo.githubusercontent.com/3aa421595f2c53ea70d5b3e2dfde9e5bd03502c4d85d75dd1d3887861a16d31e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f616e6172636869746563747572652f70697065)](https://github.com/Anarchitecture/pipe/blob/main/LICENSE)

`anarchitecture/pipe` is a small PHP library that provides functions returning **unary callables**, designed to be used with the **PHP 8.5 pipe operator** (`|>`).

The goal is to make it easy to **leverage existing functions in pipe expressions** without having to write inline closures.

Requirements
------------

[](#requirements)

- PHP **8.5+** (pipe operator support)

Installation
------------

[](#installation)

```
composer require anarchitecture/pipe
```

Quick Start
-----------

[](#quick-start)

```
use Anarchitecture\pipe as p;

$a = range(1, 8)
    |> p\array_map(fn ($x) => $x ** $x)
    |> p\array_chunk(4)
    |> p\array_map(array_sum(...));

// [288, 17650540]
```

### What a helper returns

[](#what-a-helper-returns)

Each helper provides a **unary callable**:

```
use Anarchitecture\pipe as p;

p\array_map(fn ($x) => $x * 2);
// fn (array $input) => array_map(fn ($x) => $x * 2, $input)
```

Helpers (by category)
---------------------

[](#helpers-by-category)

### Arrays

[](#arrays)

- `p\array_all(callable $callback)`
- `p\array_any(callable $callback)`
- `p\array_chunk(int $length, bool $preserve_keys = false)`
- `p\array_dissoc(string|int ...$keys)` — returns a copy of the array without the given key(s)
- `p\array_filter(callable $callback)` — filters an array, callback takes array values as single argument
- `p\array_flatten(array $arrays)` — flattens one level (array of arrays to single array). String-key clashes: later arrays overwrite earlier; numeric keys are reindexed
- `p\array_map(callable $mapper)` — maps each value to a new value (like \\array\_map); preserves keys for single-array mapping
- `p\array_map_recursive(callable $mapper)` — recursively maps leaf values in nested arrays; preserves keys at every level
- `p\array_map_recursive_with_path(callable $mapper)` — recursively maps leaf values in nested arrays; mapper is called as `$mapper($value, $path)` where `$path` is the list of keys from root to leaf (preserves keys)
- `p\array_nth(int $i)` — nth element or `null` (supports negative indexes: `-1` is last, `-2` is second-last, etc.)
- `p\array_reduce(callable $reducer, mixed $initial = null)` — reduces to a single value; reducer is called as `reducer($carry, $value)` (no key); empty input returns $initial (or `null` if omitted)
- `p\array_reduce_until(callable $reducer, callable $until, mixed $initial = null)` — reduces left-to-right until `$until($carry, $value, $key) === true`; returns `[$carry, $key, $value]` or `[$carry, null, null]` if never triggered
- `p\array_slice(int $offset, ?int $length = null, bool $preserve_keys = false)`
- `p\array_transpose()` — transpose a 2D array (matrix), preserving row/column keys (pads missing values with `null`)
- `p\array_sum(callable $callback)` — map each element over $callback then sum numeric results
- `p\array_unique(int $flags = SORT_STRING)`
- `p\sort(int $flags = SORT_REGULAR)`
- `p\rsort(int $flags = SORT_REGULAR)`
- `p\uasort(callable $comparator)` — sorts values and **preserves keys** (like PHP\\uasort)
- `p\usort(callable $comparator)` — sorts values and **reindexes keys** (like PHP\\usort)

### Strings / regex

[](#strings--regex)

- `p\explode(string $separator, int $limit = PHP_INT_MAX)`
- `p\implode(string $separator = "")`
- `p\str_replace(string|array $search, string|array $replace)`
- `p\str_starts_with(string $prefix)`
- `p\preg_match(string $pattern, int $flags = 0, int $offset = 0)` — returns the `$matches` array (empty array when no match)
- `p\preg_match_all(string $pattern, int $flags = 0, int $offset = 0)` — returns the `$matches` array (empty array when no match)
- `p\preg_replace(string|array $pattern, string|array $replacement, int $limit = -1)`

### Iterables (Generators-friendly)

[](#iterables-generators-friendly)

- `p\collect(iterable $iterable)` — **terminal**: collect any iterable into an array (preserves keys)
- `p\iterable_all(?callable $callback = null)` — returns `true` if all items match (or no item is `!== true` when callback is `null`); short-circuits
- `p\iterable_any(?callable $callback = null)` — returns `true` if any item matches (or is `=== true` when callback is `null`); short-circuits
- `p\iterable_chunk(int $size, bool $preserve_keys = false)` — lazily chunks an iterable into arrays of up to `$size` items; final chunk may be smaller; when `$preserve_keys` is `true` preserves input keys within each chunk
- `p\iterable_filter(callable $callback)` — yields matching items for which `$callback` returns `true`
- `p\iterable_first(iterable $iterable)` — returns first item or `null` (**consumes one element**)
- `p\iterable_flatten($preserve_keys = true)` — lazily flattens an iterable of iterables - preserving keys is optional, beware of key clashes
- `p\iterable_map(callable $callback)` — yields items mapped over `$callback`. Preserves keys.
- `p\iterable_nth(int $n)` — returns the nth item (0-based); consumes up to n+1 items; returns `null` if out of range
- `p\iterable_reduce(callable $callback, $initial = null)` — reduces an iterable to a single value
- `p\iterable_reduce_until(callable $reducer, callable $until, mixed $initial = null)` — reduces an iterable; returns `[$carry, $key, $value]` when triggered, or `[$carry, null, null]` if never triggered (short-circuits)
- `p\iterable_scan(callable $callback, mixed $initial = null)` — lazily yields the intermediate state after each iteration, like iterable\_reduce() but streaming every step instead of only returning the final state.
- `p\iterable_string(int $size = 1)` — lazily iterate over a string as **bytes** (`$size = 1`) or **byte-chunks** (`$size > 1`).
- `p\iterable_take(int $count)` — yields first `$count` items
- `p\iterable_ticker(int $start = 0)` — infinite counter generator
- `p\iterable_window(int $size, bool $circular = false)` – sliding windows over iterables (optionally circular)
- `p\iterable_zip(iterable ...$right)` — lazily zips the left iterable with one or more right iterables; yields tuples and stops at the shortest (preserves left keys)
- `p\iterate(callable $callback, bool $include_seed = true)` — infinite sequence by repeated application (yields seed first by default)

### Control flow

[](#control-flow)

- `p\if_else(callable $predicate, callable $then, callable $else)` — applies `$then($value)` when `$predicate($value) === true`, otherwise `$else($value)`
- `p\unless(callable $predicate, callable $callback)` — applies `$callback` only when `$predicate($value) !== true` (otherwise returns the input unchanged)
- `p\when(callable $predicate, callable $callback)` — applies `$callback` only when `$predicate($value) === true` (otherwise returns the input unchanged)

### Predicates / functional

[](#predicates--functional)

- `p\equals(mixed $value)` — returns true if `item === $value`
- `p\value(mixed $value)` — constant function returns `$value`
- `p\not(callable $callable)` — boolean invert the `$callable`'s return value

### Misc

[](#misc)

- `p\apply(callable $callback)` — applies an array of arguments to a callable (numeric keys =&gt; positional, string keys =&gt; named; mixed keys rejected)
- `p\increment(int|float $by = 1)`
- `p\tap(callable $callback)` — “tap” helper: calls `$callback($value)` for side effects and returns `$value` unchanged
- `p\zip_map(?callable $callback)` — zip semantics over multiple arrays

Semantics (intentional differences)
-----------------------------------

[](#semantics-intentional-differences)

A few helpers differ from their underlying built-ins to make pipelines pleasant:

- `p\apply($callback)` rejects arrays with mixed numeric and string keys (to avoid PHP’s “positional after named” edge cases).
- `p\array_dissoc()` removes one or more keys and returns the modified array (missing keys are ignored).
- `p\preg_match()` and `p\preg_match_all()` return the `$matches` array (like the third arg of `\preg_match()`), not the match count; no match =&gt; `[]`.
- `p\sort()`, `p\rsort()`, `p\usort()`, `p\uasort()` **return the sorted array** (native functions return `true`/`false`).
- `p\usort()` reindexes keys (it returns a list). Use `p\uasort()` when you need to preserve key associations.
- `p\zip_map($callback)([])` returns `[]` (avoids calling `array_map()` with no arrays).
- For debugging, `p\tap(\var_dump(...))` is the direct replacement for the removed `p\var_dump()`.

Examples
--------

[](#examples)

### Apply (spread arguments)

[](#apply-spread-arguments)

```
use Anarchitecture\pipe as p;

// numeric keys => positional
$out1 = [10 => "a", 20 => "b", 30 => "c"]
    |> p\apply(fn (string $a, string $b, string $c) => $a . $b . $c);

// "abc"

// string keys => named
$out2 = ["b" => 2, "a" => 1]
    |> p\apply(fn (int $a, int $b) => $a - $b);

// -1
```

### Conditional transform

[](#conditional-transform)

```
use Anarchitecture\pipe as p;

$out = "  Hello  "
    |> p\when(is_string(...), trim(...))
    |> p\when(p\equals("Hello"), p\value("bye"));

// "bye"
```

### If / else branching

[](#if--else-branching)

```
use Anarchitecture\pipe as p;

$out = "Hello"
    |> p\if_else(
        p\equals("Hello"),
        p\value("bye"),
        p\value("unknown")
    );

// "bye"
```

### Working with iterables (lazy pipelines)

[](#working-with-iterables-lazy-pipelines)

```
use Anarchitecture\pipe as p;

$result = 0
    |> p\iterate(static fn(int $x) : int => $x + 1)
    |> p\iterable_take(4)
    |> p\collect(...);

// [0, 1, 2, 3]
```

### Zip-map (multiple arrays)

[](#zip-map-multiple-arrays)

```
use Anarchitecture\pipe as p;

$sumPairs = [[6, 7, 8], [10, 20, 30]]
    |> p\zip_map(fn ($a, $b) => $a + $b);

// [16, 27, 38]
```

### Array dissoc (remove keys)

[](#array-dissoc-remove-keys)

```
use Anarchitecture\pipe as p;

$user = [
    'id' => 123,
    'email' => 'a@example.com',
    'password_hash' => '...',
];

$public = $user
    |> p\array_dissoc('password_hash');

// ['id' => 123, 'email' => 'a@example.com']
```

### Tap (debug/log without breaking the pipeline)

[](#tap-debuglog-without-breaking-the-pipeline)

```
use Anarchitecture\pipe as p;

$out = "  Hello  "
    |> trim(...)
    |> p\tap(\var_dump(...))      // debug
    |> strtoupper(...);

// prints "Hello", returns "HELLO"
```

### Array transpose (matrix)

[](#array-transpose-matrix)

For numeric matrices it behaves like a regular transpose:

```
use Anarchitecture\pipe as p;

$matrix = [
    [1, 2, 3],
    [4, 5, 6],
];

$t = $matrix
    |> p\array_transpose();

// [
//  [1, 4],
//  [2, 5],
//  [3, 6]
//]
```

For string keyed matrices, it pads missing cells with null:

```
use Anarchitecture\pipe as p;

$matrix = [
    'r1' => ['a' => 1, 'b' => 2],
    'r2' => ['a' => 3, 'c' => 4],
];

$t = $matrix
    |> p\array_transpose();

// [
//   'a' => ['r1' => 1,    'r2' => 3],
//   'b' => ['r1' => 2,    'r2' => null],
//   'c' => ['r1' => null, 'r2' => 4],
// ]
```

### Iterable zip

[](#iterable-zip)

```
use Anarchitecture\pipe as p;

$result = [1, 2]
    |> p\iterable_zip([10, 20], [100, 200])
    |> p\collect(...);

// [
//  [1, 10, 100],
//  [2, 20, 200]
//]
```

### Sliding windows (iterables)

[](#sliding-windows-iterables)

```
use Anarchitecture\pipe as p;

// linear (default): full windows only, no wraparound
$linear = [1, 2, 3, 4, 5, 6]
    |> p\iterable_window(3)
    |> p\collect(...);

// [
//   [1, 2, 3],
//   [2, 3, 4],
//   [3, 4, 5],
//   [4, 5, 6],
// ]

// circular: adds the boundary-crossing windows (end -> start)
$circular = [0, 1, 2, -2, -1]
    |> p\iterable_window(size: 4, circular: true)
    |> p\collect(...);

// [
//   [0, 1, 2, -2],
//   [1, 2, -2, -1],
//   [2, -2, -1, 0],
//   [-2, -1, 0, 1],
//   [-1, 0, 1, 2],
// ]
```

Philosophy
----------

[](#philosophy)

- functions return unary callables
- explicitly designed for pipe expressions
- thin wrappers around existing PHP functions
- small, predictable, and composable
- no magic, just functions

Status
------

[](#status)

Experimental — based on PHP 8.5 pipes.

License
-------

[](#license)

MIT

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance89

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 98.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Recently: every ~14 days

Total

37

Last Release

53d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/69cc228b96942fbad8887cd5910708f6451f2fded988bd7fa65129848ef75156?d=identicon)[lrhoek](/maintainers/lrhoek)

---

Top Contributors

[![lrhoek](https://avatars.githubusercontent.com/u/10499457?v=4)](https://github.com/lrhoek "lrhoek (112 commits)")[![timfennis](https://avatars.githubusercontent.com/u/1632739?v=4)](https://github.com/timfennis "timfennis (2 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/anarchitecture-pipe/health.svg)

```
[![Health](https://phpackages.com/badges/anarchitecture-pipe/health.svg)](https://phpackages.com/packages/anarchitecture-pipe)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
