Skip to content

Anarchitecture/pipe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

anarchitecture/pipe

CI Latest Version 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

  • PHP 8.5+ (pipe operator support)

Installation

composer require anarchitecture/pipe

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

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)

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

  • 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)

  • 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_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_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_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

  • 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

  • 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

  • p\apply(callable $callback) — applies an array of arguments to a callable (numeric keys => positional, string keys => 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)

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 => [].
  • 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

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

use Anarchitecture\pipe as p;

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

// "bye"

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)

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)

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)

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)

use Anarchitecture\pipe as p;

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

// prints "Hello", returns "HELLO"

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

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)

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

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

Status

Experimental — based on PHP 8.5 pipes.

License

MIT

About

Unary callable helpers to leverage PHP 8.5 pipes

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages