PHP FUNCTIONAL UTILITY LIBRARY
What is it?
Idles is a PHP functional utility library, a port of Javascript Lodash/Fp and
Ramda libraries to PHP language .
It comprises a set of side-effect free , immutable and automatically curried functions that support lazy evaluation .
The iterable collection parameter is usually supplied last to make currying convenient.
Such design makes it easy to create functional pipelines with a possibility of delayed evaluation.
Installation
composer require miroshnikov/idles
Usage
All methods are in Idles\ namespace, immutable , pure and auto-curried .
Binary safe, mb_* functions are used for string methods.
The comparison everywhere by default is a weak equality check (==) .
Usage example:
use function Idles\{pipe, map, divide, ary, partial, curryN, filter};
use const Idles\_;
pipe(
map(divide(_, 2)),
map(ary(1, partial(\round(...), [_, 0]))),
map(curryN(1, \intval(...))),
filter(fn ($n) => $n % 2)
)([2,3,4,8]);
Lazy evaluation
Most of the functions take any kind of iterable as a collection parameter and become
lazy when given an Iterator or Generator as an input.
When piped intermediate lazy operations are applied to every element of the iterator one after the other without collection all elements in memory array.
Lazy pipelines operate on a "pull," rather than a "push" basis.
Although when given an array such method will NOT be lazy and return a modified array like a build-in PHP array_... function.
The rule is: you will get back the same kind of iterable that you passed in as an argument .
collect function may be used to turn an iterable of any kind into an array.
icon marks lazy methods.
use function Idles\{pipe, map, filter, collect};
$generator = (function () {
$fp = \fopen('/huge/file/with/numbers', 'r');
while (($s = \fgets($fp)) !== false) {
yield $s;
}
})();
$iterator = pipe(
map(fn ($v) => \intval(\trim($v), 10)),
filter(fn ($v) => $v % 2 == 0),
map(fn ($v) => "[$v]")
// ...
)($generator);
// nothing has happened so far, no data has been requested
// now you can iterate over elements of $iterator with foreach
// or convert it into an array in memory by iterator_to_array or collect
$array = collect($iterator);
Array vs Record
The Idles library makes a distinction between arrays and records.
Array has only numerical sequential indexes. This is what the Array is in JavaScript and many other languages.
Record may have both numerical and string keys.
AKA hash, map, object, hash table, or associative array in other languages.
This is what the Object is in JavaScript.
icon marks methods that do not retain string keys and return indexed iterables.
filter(fn ($v) => $v == 'a' || $v == 'C')(['a', 'b', 'c' => 'C']); // ['a', 'C']
Placeholder
Idles\_ is a special placeholder used to specify "gaps" within curried or partially applied functions.
use function Idles\{curryN, partial};
use const Idles\_;
$greet = curryN(3, \str_replace(...))('{name}', _, 'Hello, {name}!');
// or
$greet = partial(\str_replace(...), ['{name}', _, 'Hello, {name}!']);
$greet('Alice'); // Hello, Alice!
add($a, $b)
Calculates the sum of two numbers.
Parameters
\number
$a
The first number in an addition.
\number
$b
The second number in an addition.
Examples
add(100)(13); // 113
all($predicate, $collection)
Checks if $predicate returns truthy for all elements of $collection. Stop once it returns falsey.
Parameters
callable(mixed $value, array-key $key): bool
$predicate
?iterable
$collection
Examples
all('\is_numeric')([1,2,3]); // true
$users = [
[ 'user' => 'barney', 'age' => 36, 'active' => true ],
[ 'user' => 'fred', 'age' => 40, 'active' => true ]
];
all(property('active'))($users); // true
allPass($predicates)
Returns a function that checks if its arguments pass all $predicates.
Parameters
array<callable(mixed ...): bool>
$predicates
Returns
callable(mixed ...): bool
a curried function whose arity matches that of the highest-arity predicate
Examples
$bothStrings = fn (...$args) => all(ary(1, \is_string(...)), $args);
$equal = fn ($a, $b) => $a == $b;
allPass([$bothStrings, $equal])('a', 'b'); // false
allPass([$bothStrings, $equal])('a', 'a'); // true
allPass([$bothStrings, $equal])(1, 1); // false
always($value)
Returns a function that always returns the given value.
Template types
T of mixed
any($predicate, $collection)
Checks if $predicate returns truthy for any element of $collection. Stops on first found.
Parameters
callable(mixed $value, mixed $key): bool
$predicate
?iterable
$collection
Examples
$users = [
[ 'user' => 'barney', 'active' => false ],
[ 'user' => 'fred', 'active' => true ]
];
any(propEq('active', true), $users); // true
anyPass($predicates)
Returns a function that checks if its arguments pass any of the $predicates.
Parameters
array<callable(mixed ...): bool>
$predicates
Returns
callable(mixed ...): bool
a curried function whose arity matches that of the highest-arity predicate
Examples
$bothStrings = fn (...$args) => all(ary(1, \is_string(...)), $args);
$equal = fn ($a, $b) => $a == $b;
anyPass([$bothStrings, $equal])('a', 'b'); // true
anyPass([$bothStrings, $equal])('1', 2); // false
anyPass([$bothStrings, $equal])(1, 1); // true
apply($fn, $args)
Parameters
callable(mixed ...): mixed
$fn
?iterable<mixed>
$args
Examples
apply(\max(...), [1, 2, 3, -99, 42, 6, 7]); // 42
applyTo($value, $interceptor)
Returns the result of $interceptor($value).
Template types
T of mixed
Parameters
\T
$value
callable(\T $value): mixed
$interceptor
Examples
$n13 = applyTo(13);
$n13(add(100)); // 113
ary($n, $fn)
Creates a function that invokes $fn, with up to $n arguments, ignoring any additional arguments.
Parameters
positive-int
$n
callable
$fn
Examples
map(ary(1, \intval(...)), ['6', '8', '10']); // [6, 8, 10]
ascend($fn, $a, $b)
Makes an ascending comparator function out of a function that returns a value that can be compared with <=>.
Template types
T of mixed
Parameters
callable(\T): numeric|string|array
$fn
\T
$a
\T
$b
Returns
-1|0|1
$a<$b | $a==$b | $a>$b
Examples
$byAge = ascend(prop('age'));
$people = [
[ 'name' => 'Emma', 'age' => 70 ],
[ 'name' => 'Peter', 'age' => 78 ],
[ 'name' => 'Mikhail', 'age' => 62 ],
];
sort($byAge, $people); // Mikhail, Emma, Peter
attempt($fn, $args)
Calls $fn, returning either the result or the caught exception.
Parameters
callable
$fn
mixed[]
$args
Examples
attempt(fn () => 'A'); // A
attempt(fn () => throw new \Exception('Error')); // Exception('Error')
both($fn1, $fn2)
Resulting function returns $fn1(...$args) if it is falsy or $fn2(...$args) otherwise, short-circuited.
Parameters
callable
$fn1
callable
$fn2
Examples
both(identity(...), always(''))('value'); // ''
both(always('a'), identity(...))('b'); // b
camelCase($s)
Converts string to camel case.
Examples
camelCase('--foo-bar--'); // fooBar
capitalize($string)
Converts the first character of string to upper case and the remaining to lower case.
Examples
capitalize('FRED'); // Fred
collect($collection)
Collects any iterable into array
Template types
T of mixed
Parameters
?iterable<\T>
$collection
compose(...$fns)
Like pipe but invokes the functions from right to left.
Examples
compose('\strtoupper', fn ($s) => 'hello '.$s, '\trim')(' fred '); // 'HELLO FRED'
concat($iterable, $value)
Concatinates an iterable with an iterable/value.
Parameters
iterable<mixed>
$iterable
iterable<mixed>|mixed
$value
Returns
iterable<mixed>
Numerically indexed concatenated iterable
Examples
concat(['a','b'], ['c', 'd']); // ['a', 'b', 'c', 'd']
concat(['a','b'], 'C'); // ['a', 'b', 'C']
concatAll($values)
Concatinates an iterable with additional iterables/values
Parameters
array<iterable<mixed>|mixed>
$values
Returns
iterable<mixed>
Numerically indexed concatenated iterable
cond($pairs)
Iterates over $pairs and invokes the corresponding function of the first predicate to return truthy.
Parameters
array<array{callable(mixed): bool, callable}>
$pairs
array of [predicate, function] tuples.
Examples
$fn = cond([
[equals(0), always('water freezes at 0°C')],
[equals(100), always('water boils at 100°C')],
[T(...), fn ($temp) => "nothing special happens at $temp °C"]
]);
$fn(0); // 'water freezes at 0°C'
$fn(50); // 'nothing special happens at 50 °C'
$fn(100); // 'water boils at 100°C'
count($predicate, $collection)
Counts the number of items in $collection matching the $predicate
Parameters
callable(mixed $v): bool
$predicate
?iterable
$collection
Examples
$even = fn ($x) => $x % 2 == 0;
count($even, [1, 2, 3, 4, 5]); // 2
countBy($iteratee, $collection)
Returns an array<result of $iteratee($value), number of times the $iteratee($value) was found in $collection>
Parameters
callable(mixed $value): array-key
$iteratee
?iterable
$collection
Examples
$numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
countBy(\floor(...))($numbers); // [1 => 3, 2 => 2, 3 => 1]
curry($fn)
\Idles\_ const may be used as a placeholder.
Examples
use const \Idles\_;
$abc = fn ($a, $b, $c) => $a.$b.$c;
curry($abc)('a')('b')('c'); // 'abc'
curry($abc)(_, 'b')(_, 'c')('a'); // 'abc'
curryN($arity, $fn)
Curry with fixed arity. \Idles\_ const may be used as a placeholder.
Examples
$sum = fn (int ...$nums) => \array_sum($nums);
curryN(2, $sum)(2)(3); // 5
curryRight($f)
Like curry but arguments are prepended.
Examples
$abc = fn ($a, $b, $c) => $a.$b.$c;
curryRight($abc)('c')('b')('a'); // 'abc'
curryRightN($arity, $f)
Like curryN but arguments are prepended.
Examples
$join = fn (string ...$strings) => \implode(',', $strings);
curryRightN(3, $join)('c')('b')('a'); // a,b,c
dec($number)
defaultTo($default, $value)
Returns the first argument if it is truthy, otherwise the second argument.
Parameters
mixed
$default
mixed
$value
Examples
defaultTo(10, null); // 10
descend($fn, $a, $b)
Makes an descending comparator function out of a function that returns a value that can be compared with <=>.
Template types
T of mixed
Parameters
callable(\T): numeric|string|array
$fn
\T
$a
\T
$b
Returns
-1|0|1
$a<$b | $a==$b | $a>$b
Examples
$byAge = descend(prop('age'));
$people = [
[ 'name' => 'Emma', 'age' => 70 ],
[ 'name' => 'Peter', 'age' => 78 ],
[ 'name' => 'Mikhail', 'age' => 62 ],
];
sort($byAge, $people); // Peter, Emma, Mikhail
divide($a, $b)
Parameters
int|float
$a
int|float
$b
drop($n, $collection)
Skips the first $n elemens and returns the rest of iterable or string.
Template types
T of iterable<mixed>|string
Parameters
int
$n
\T|null
$collection
Examples
drop(1, [1, 2, 3]); // [2, 3]
dropLast($n, $collection)
Skips the last $n elements of iterable or string.
Template types
T of iterable<mixed>|string
Parameters
int
$n
\T|null
$collection
Examples
dropLast(2, [1, 2, 3]); // [1]
each($iteratee, $collection)
Iterates over elements of $collection. Iteratee may exit iteration early by returning false.
Parameters
?callable(mixed $value, array-key $key, iterable $collection): bool
$iteratee
?iterable
$collection
Returns
iterable<mixed>|null
the original collection
either($fn1, $fn2)
Resulting function returns $fn1(...$args) if it is truthy or $fn2(...$args) otherwise, short-circuited.
Parameters
callable
$fn1
callable
$fn2
Examples
either(always('a'), identity(...))('b'); // a
either(always(''), identity(...))('b'); // b
eq($a, $b)
equals($a, $b)
escapeRegExp($s)
Escapes regular expression.
evolve($transformations, $record)
Creates a new record by recursively calling transformation functions with $record properties.
Parameters
array<string, callable(mixed): mixed>
$transformations
?iterable<string, mixed>
$record
Examples
$tomato = ['firstName' => ' Tomato ', 'data' => ['elapsed' => 100, 'remaining' => 1400], 'id' => 123];
$transformations = [
'firstName' => '\trim',
'lastName' => '\trim', // Will not get invoked.
'data' => [
'elapsed' => add(1),
'remaining' => add(-1)
]
];
evolve($transformations)($tomato);
// ['firstName' => 'Tomato', 'data' => ['elapsed' => 101, 'remaining' => 1399], 'id' => 123]
F(...$args)
filter($predicate, $collection)
Returns elements $predicate returns truthy for.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
?iterable
$collection
Examples
filter('is_numeric', ['a', 'b', 13]); // [13]
find($predicate, $collection)
Returns the first element $predicate returns truthy for.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
?iterable
$collection
findFrom($predicate, $fromIndex, $collection)
Returns the first element $predicate returns truthy for starting from $fromIndex.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
int
$fromIndex
?iterable
$collection
findIndex($predicate, $collection)
Returns the index of the first element predicate returns truthy for or -1 if not found.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
?iterable
$collection
Examples
findIndex(fn ($v) => $v == 'b', ['a', 'b', 'c'])); // 1
findIndexFrom($predicate, $fromIndex, $collection)
Returns the index of the first element $predicate returns truthy for starting from $fromIndex.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
int
$fromIndex
?iterable
$collection
Examples
findIndexFrom(fn ($v) => $v == 'b', -2, ['a','b','a','b','c']) // 3
findLastIndex($predicate, $collection)
Returns the index of the last element predicate returns truthy for, -1 if not found.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
?iterable
$collection
Examples
findLastIndexFrom(fn ($v) => $v == 'b', 2, ['a', 'b', 'a', 'b']); // 1
findLastIndexFrom($predicate, $fromIndex, $collection)
Returns the index of the last element $predicate returns truthy for starting from $fromIndex.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
int
$fromIndex
?iterable
$collection
flatMap($iteratee, $collection)
Parameters
callable(mixed $value, array-key $key, iterable $collection): mixed
$iteratee
?iterable
$collection
Examples
flatMap(fn ($n) => [$n, $n], [1,2]); // [1, 1, 2, 2]
flatMapDepth($iteratee, $depth, $collection)
Maps and flattens the mapped results up to $depth times.
Parameters
callable(mixed $value, array-key $key, iterable $collection): mixed
$iteratee
int
$depth
?iterable
$collection
Examples
flatMapDepth(fn ($n) => [[[$n, $n]]], 2, [1, 2]); // [[1, 1], [2, 2]];
flatten($collection)
Flattens iterable a single level deep.
Examples
flatten(['a' => 'A', ['b' => 'B'], 'c' => 'C']); // ['A', 'B', 'C']
flattenDepth($depth, $collection)
Recursively flatten array up to $depth times.
Parameters
int
$depth
?iterable
$collection
flip($fn)
Returns a new curried function with the first two arguments reversed.
Examples
flip(fn ($a, $b, $c, $d) => [$a, $b, $c, $d])(1, 2)(3, 4); // [2, 1, 3, 4]
flow($funcs)
Left-to-right function composition. The first argument may have any arity; the remaining arguments must be unary.
fromPairs($collection)
Creates a new record from a list key-value pairs. The inverse of toPairs.
Parameters
?iterable<array{array-key, mixed}>
$collection
Examples
fromPairs([['a', 1], ['b', 2], ['a', 3]]); // ['a' => 3, 'b' => 2]
groupBy($iteratee, $collection)
Creates an array composed of keys generated from running each value through $iteratee.
Parameters
callable(mixed $value): mixed
$iteratee
?iterable<mixed>
$collection
Returns
array<array-key, mixed[]>
Examples
groupBy('strlen')(['one', 'two', 'three']); // [ '3' => ['one', 'two'], '5' => ['three'] ]
gt($a, $b)
Examples
gt(100)(13); // true
gte($a, $b)
Examples
gte(13)(13); // true
has($key, $record)
Checks if $record has $key.
Parameters
array-key
$key
?iterable<mixed>
$record
Examples
has('a', ['a' => 'A]); // true
hasPath($path, $record)
Checks if $path exists in $record.
Parameters
(array-key)|array<array-key>|string
$path
?iterable<mixed>
$record
Examples
$r = [ 'a' => [ 'b' => 2 ] ];
hasPath('a', $r); // true
hasPath(['a', 'b'], $r); // true
hasPath('a.b', $r); // true
head($collecton)
Gets the first element of $collecton.
Parameters
?iterable<mixed>
$collecton
Examples
head([1, 2, 3]); // 1
identity($value)
Returns the first argument it receives.
Template types
T of iterable<mixed>|string
ifElse($predicate, $onTrue, $onFalse)
Resulting function returns $onTrue(...$args) if $predicate(...$args) is truthy or $onFalse(...$args) otherwise.
Parameters
callable(mixed ...): bool
$predicate
callable(mixed ...): mixed
$onTrue
callable(mixed ...): mixed
$onFalse
Returns
callable(mixed ...): mixed
Examples
$f = ifElse(equals('a'), always('T'), always('F'));
$f('a'); // T
$f('b'); // F
inc($number)
includes($value, $collection)
Checks if $value is in iterable/string.
Parameters
mixed
$value
iterable<mixed>|null|string
$collection
Examples
includes(1, ['a' => 1, 'b' => 2]); // true
includesFrom($value, $fromIndex, $collection)
Checks if $value is in iterable/string, starting from $fromIndex.
Parameters
mixed
$value
int
$fromIndex
iterable<mixed>|null|string
$collection
indexBy($iteratee, $collection)
Creates a record composed of keys generated from the results of running each element of $collection through $iteratee.
Parameters
callable(mixed): array-key
$iteratee
?iterable<mixed>
$collection
Examples
$a = [ [ 'code' => 97 ], [ 'code' => 100 ] ];
indexBy(fn ($r) => \chr($r['code']), $a); // ['a' => [ 'code' => 97 ], 'd' => [ 'code' => 100 ]]
indexOf($item, $collection)
Returns the index of the first occurrence of the item in an iterable or string, else -1.
Parameters
mixed
$item
iterable<mixed>|string
$collection
Examples
indexOf(2, [1, 2, 1, 2]); // 1
indexOfFrom($item, $fromIndex, $collection)
Returns the index of the first occurrence of the item in an iterable or string, starting from $fromIndex, else -1.
Parameters
mixed
$item
int
$fromIndex
iterable<mixed>|string
$collection
intersection($array1, $array2)
Returns unique values that are included in both arrays.
Parameters
?iterable
$array1
?iterable
$array2
Examples
intersection(['a', 'a', 'b'], ['c', 'a', 'a']); // ['a']
intersectionBy($iteratee, $array1, $array2)
Like intersection but invokes $iteratee for each element before comparison.
Parameters
callable(mixed): mixed
$iteratee
?iterable
$array1
?iterable
$array2
Examples
intersectionBy('\floor', [2.1, 1.2], [2.3, 3.4]); // [2.1]
intersectionWith($comparator, $array1, $array2)
Like intersection but invokes $comparator to compare elements.
Parameters
callable(mixed $a, mixed $b): int
$comparator
e.g. $a <=> $b
?iterable
$array1
?iterable
$array2
Examples
intersectionWith(fn ($a, $b) => $a <=> $b, ['a', 'a', 'b'], ['c', 'a', 'a']); // ['a']
invert($collection)
Replaces keys with values. Duplicate keys are overwritten.
Parameters
?iterable<array-key>
$collection
Examples
invert([ 'a' => 1, 'b' => 2, 'c' => 1 ]); // [1 => 'c', 2 => 'b']
iterate($fn, $value)
Returns a generator of $value, $f($value), $f($f($value)) etc.
Parameters
callable
$fn
mixed
$value
initial
Examples
pipe(
take(5),
collect(...)
)(iterate(inc(...), 1)); // [1, 2, 3, 4, 5]
join($separator, $collection)
Joins iterable elements separated by $separator.
Parameters
string
$separator
?iterable
$collection
Examples
join('~', ['a', 'b', 'c']); // 'a~b~c'
just($value)
Returns an Optional with the specified non-null value
Examples
just('abc')->map(\strtoupper(...))->get(); // ABC
just(113)
->filter(fn($n) => $n > 100)
->filter(fn($n) => $n < 120)
->get(); // 113
juxt($iteratees)
Applies a list of functions to a list of values.
Returns
callable(mixed ...): mixed[]
Examples
juxt([\max(...), \min(...)])(1,2,3,4); // [4,1]
$isOdd = fn ($n) => $n % 2;
juxt([filter($isOdd), remove($isOdd)])([1,2,3,4,5,6,7,8,9]);
// [[1,3,5,7,9], [2,4,6,8]]
keys($record)
Returns an indexed iterable of keys in $record.
Parameters
?iterable<string, mixed>
$record
Examples
keys([ 'a'=> 1, 'b'=> 2, 'c'=> 3 ]); // ['a', 'b', 'c']
last($collecton)
Gets the last element of iterable.
Parameters
?iterable<mixed>
$collecton
Examples
last([1, 2, 3]); // 3
lastIndexOf($item, $collection)
Returns the index of the last occurrence of $value in iterable or string, else -1.
Parameters
mixed
$item
iterable<mixed>|string
$collection
Examples
lastIndexOf(3, [-1,3,3,0,1,2,3,4]); // 6
length($value)
Returns size of a countable, number of parameters of a function, lenght of string or number of properties of an object.
Parameters
mixed[]|object|string|callable
$value
lt($a, $b)
Examples
lt(100)(13); // false
lte($a, $b)
Examples
lte(13)(13); // true
map($iteratee, $collection)
Run each element in $collection through $iteratee.
Parameters
callable
$iteratee
?iterable<array-key, mixed>
$collection
Examples
map(fn ($n) => $n * $n, [4, 8]); // [16, 64]
memoize($fn)
Creates a function that memoizes the result of $fn.
memoizeWith($resolver, $fn)
Creates a function that memoizes the result of $fn. $resolver returns map cache key (args[0] by default).
Parameters
callable(mixed ...): array-key
$resolver
callable
$fn
merge($left, $right)
Merges properties, numeric keys are replaced .
Parameters
?iterable
$left
?iterable
$right
Examples
merge(['a', 'c' => 'C'], ['b', 'd' => 'D']); // ['b', 'c' => 'C', 'd' => 'D']
mergeAll($iterables)
Merges properties, numeric keys are replaced .
Parameters
array<iterable<mixed>>
$iterables
mergeDeep($left, $right)
Merges properties recursively, numeric keys are replaced .
Parameters
?iterable
$left
?iterable
$right
Examples
$a = ['a' => ['b' => 1, 'c' => 'C'], ['e' => 'E'], 'x'];
$b = ['a' => ['b' => 2, 'd' => 'D'], ['f' => 'F'], 'y'];
mergeDeep([$a, $b]);
// ['a' => ['b' => [1, 2], 'c' => 'C', 'd' => 'D'], ['e' => 'E'], 'x', ['f' => 'F'], 'y'],
mergeWith($customizer, $left, $right)
Like merge but if a key exists in both records, $customizer is called to the values associated with the key.
Parameters
callable(mixed $a, mixed $b): mixed
$customizer
?iterable<mixed>
$left
?iterable<mixed>
$right
Examples
mergeWith(concat(...), ['a' => [1], 'b' => [2]], ['a' => [3], 'b' => [4]]);
// ['a' => [1,3], 'b' => [2,4]]
modifyPath($path, $updater, $record)
Creates new record by applying an $updater function to the value at the given $path.
Parameters
array<array-key>|(array-key)
$path
callable(mixed): mixed
$updater
?iterable<mixed>
$record
Examples
$a = [ 'a' => [ [ 'b' => [ 'c' => 3 ] ] ] ];
modifyPath(['a',0,'b','c'], fn ($n) => $n*$n, $a); // [ 'a' => [ [ 'b' => [ 'c' => 9 ] ] ] ]
modulo($a, $b)
multiply($a, $b)
negate($predicate)
Creates a function that negates the result of the $predicate function.
Examples
$isEven = fn ($n) => $n % 2 == 0;
filter(negate($isEven), [1, 2, 3, 4, 5, 6]); // [1, 3, 5]
not($a)
nothing()
Returns an empty Optional.
Examples
nothing()->map(\strtoupper(...))->orElse('ABC'); // ABC
now()
Returns the timestamp of the number of seconds
nth($offset, $collection)
Returns the $offset element. If $offset is negative the element at index length + $offset is returned.
Parameters
int
$offset
?iterable<mixed>
$collection
Examples
$list = ['foo', 'bar', 'baz', 'quux'];
nth(1, $list); // 'bar'
nth(-1, $list); // 'quux'
nth(99, $list); // null
nthArg($n)
Returns a function which returns its $nth argument.
Examples
nthArg(1)('a', 'b', 'c'); // b
nthArg(-1)('a', 'b', 'c'); // c
objOf($key, $value)
Creates an array containing a single key => value pair.
Examples
$matchPhrases = compose(
objOf('must'),
map(objOf('match_phrase'))
);
$matchPhrases(['foo', 'bar', 'baz']);
// ["must" => [["match_phrase" => 'foo'], ["match_phrase" => 'bar'], ["match_phrase" => 'baz']]]
omit($keys, $collection)
The opposite of pick. Returns record without $keys.
Parameters
string[]
$keys
?iterable<string, mixed>
$collection
Examples
omit(['a', 'd'], ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]);
// ['b' => 2, 'c' => 3]
omitBy($predicate, $collection)
The opposite of pickBy. Returns properties of $record that $predicate returns falsey for.
Parameters
callable(mixed $value, string $key): bool
$predicate
?iterable<string, mixed>
$collection
Examples
omitBy(unary('\is_int'), ['a' => 1, 'b' => '2', 'c' => 3]); // ['b' => '2']
once($fn)
$fn is only called once, the first value is returned in subsequent invocations.
Examples
$addOneOnce = once(fn ($x) => $x + 1);
$addOneOnce(10); // 11
$addOneOnce(50); // 11
interface Optional
{
/**
* @return bool true if not empty
*/
public function isPresent(): bool;
/**
* @return bool true if empty
*/
public function isEmpty(): bool;
/**
* Returns value, throw exception if empty
*/
public function get(): mixed;
/**
* Returns the contained value if the optional is nonempty or `$default`
*/
public function orElse(mixed $default): mixed;
/**
* Returns the contained value, if present, otherwise throw an exception
*/
public function orElseThrow(\Exception $e = new \Exception('No value on None')): mixed;
/**
* If a value is present, apply the `$fn` to it, and if the result is non-null, return an Optional describing the result
*/
public function map(callable $fn): Optional;
/**
* Use instead of map if $f returns Optional
*/
public function flatMap(callable $fn): Optional;
/**
* If a value is present and matches the `$predicate`, return an Optional with the value, otherwise an empty Optional.
*/
public function filter(callable $predicate): Optional;
}
Maybe/Option monad (container) which may or may not contain a non-null value.
orderBy($iteratees, $orders, $collection)
Like sortBy but allows specifying the sort orders.
Parameters
array<callable(mixed $value): mixed>
$iteratees
array<"asc"|"desc">
$orders
?iterable<mixed>
$collection
Examples
$users = [
[ 'user' => 'fred', 'age' => 48 ],
[ 'user' => 'barney', 'age' => 34 ],
[ 'user' => 'fred', 'age' => 40 ],
[ 'user' => 'barney', 'age' => 36 ]
];
orderBy([property('user'), property('age')], ['asc', 'desc'], $users);
// [
// [ 'user' => 'barney', 'age' => 36 ],
// [ 'user' => 'barney', 'age' => 34 ],
// [ 'user' => 'fred', 'age' => 48 ],
// [ 'user' => 'fred', 'age' => 40 ]
// ]
partial($fn, $partials)
Creates a function that invokes $fn with $partials prepended to the arguments. \Idles\_ const may be used as a placeholder.
Parameters
callable
$fn
mixed[]
$partials
Examples
use const \Idles\_;
$abcd = fn ($a, $b, $c, $d) => $a.$b.$c.$d;
partial($abcd, ['a', _, 'c'])('b', 'd'); // 'abcd'
partialRight($fn, $partials)
Like partial but $partials are appended .
Parameters
callable
$fn
mixed[]
$partials
Examples
use const \Idles\_;
$abcd = fn ($a, $b, $c, $d) => $a.$b.$c.$d;
partialRight($abcd, ['b', _, 'd'])('a', 'c')); // 'abcd'
partition($predicate, $collection)
Split $collection into two groups, the first of which contains elements $predicate returns truthy for, the second of which contains elements $predicate returns falsey for.
Parameters
callable(mixed $value): bool
$predicate
?iterable<mixed>
$collection
Examples
partition(
fn ($v) => stripos($v, 'A') !== false,
['a' => 'AA', 'b' => 'BB', 'c' => 'AAA']
);
// [['a' => 'AA', 'c' => 'AAA'], ['b' => 'BB']]
path($path, $collection)
Retrieve the value at a given path.
Parameters
(array-key)|array<array-key>|string
$path
?iterable<mixed>
$collection
Examples
$rec = [ 'a' => [[ 'b' => [ 'c' => 3 ] ]] ];
path(['a', '0', 'b', 'c'], $rec); // 3
path('a[0].b.c', $rec); // 3
pathOr('default', 'a.b.c', $rec); // 'default'
pathOr($default, $path, $collection)
Retrieve the value at a given path. If path is not found, the $default is returned.
Parameters
mixed
$default
(array-key)|array<array-key>|string
$path
?iterable<mixed>
$collection
Examples
$rec = [ 'a' => [[ 'b' => [ 'c' => 3 ] ]] ];
path(['a', '0', 'b', 'c'], $rec); // 3
path('a[0].b.c', $rec); // 3
pathOr('default', 'a.b.c', $rec); // 'default'
paths($paths, $collection)
Keys in, values out. Order is preserved.
Parameters
array<(array-key)|array<array-key>|string>
$paths
?iterable<mixed>
$collection
Examples
$a = [ 'a' => [ [ 'b' => [ 'c' => 3 ] ], 4] ];
paths([['a',0,'b','c'], ['a',0,'z'], ['a',1]], $a); // [3, null, 4]
paths(['a.0.b.c', 'a.0.z', 'a.1'], $a); // [3, null, 4]
pick($keys, $collection)
Returns record containing only $keys.
Parameters
array<array-key>
$keys
?iterable<mixed>
$collection
Examples
pick(['a', 'd'], ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]);
// ['a' => 1, 'd' => 4]
pickBy($predicate, $collection)
Returns record containing only keys $predicate returns truthy for.
Parameters
callable(mixed $value, array-key $key): bool
$predicate
?iterable<mixed>
$collection
Examples
$isUpperCase = fn ($val, $key) => \strtoupper($key) == $key;
pickBy($isUpperCase, ['a' => 1, 'b' => 2, 'A' => 3, 'B' => 4]);
// ['A' => 3, 'B' => 4]
pipe(...$fns)
Left-to-right function composition. The first argument may have any arity; the remaining arguments must be unary.
Examples
pipe('\trim', '\strtoupper')(' hello '); // 'HELLO'
pluck($key, $collection)
Returns a new array by plucking the same named property off all records in the array supplied.
Parameters
array-key
$key
?iterable<array>
$collection
Examples
pluck(0, [[1, 2], [3, 4]]); // [1, 3]
pluck('val', ['a' => ['val' => 3], 'b' => ['val' => 5]]); // ['a' => 3, 'b' => 5]
project($props, $collection)
Like SQL select statement.
Parameters
array<array-key>
$props
?iterable<mixed[]>
$collection
Examples
$kids = [
[ 'name' => 'Abby', 'age' => 7, 'hair' => 'blond', 'grade' => 2 ],
[ 'name' => 'Fred', 'age' => 12, 'hair' => 'brown', 'grade' => 7 ]
];
project(['name', 'grade'], $kids); // [['name' => 'Abby', 'grade' => 2], [ 'name' => 'Fred', 'grade' => 7 ]]
prop($key, $record)
Return the specified property.
Parameters
array-key
$key
?iterable<mixed>
$record
Examples
propOr('NO', 'b', ['a' => 'A']); // 'NO'
propEq($key, $value, $record)
Returns $record[$key] == $value
Parameters
array-key
$key
mixed
$value
?iterable<mixed>
$record
Examples
propEq('a', 'A', ['a' => 'A']); // true
propOr($default, $key, $record)
Return the $key property or $default.
Parameters
mixed
$default
array-key
$key
?iterable<mixed>
$record
rearg($indexes, $fn)
Returns a curried function that invokes $fn with arguments rearranged according to $indexes.
Parameters
array<non-negative-int>
$indexes
callable
$fn
Examples
$rearged = rearg(
[2, 0, 1],
fn ($a, $b, $c) => [$a, $b, $c]
);
$rearged('b', 'c', 'a'); // ['a', 'b', 'c']
reduce($iteratee, $accumulator, $collection)
Reduces $collection to a value which is the accumulated result of running each element in collection through $iteratee.
Parameters
callable(mixed $accumulator, mixed $value, array-key $key, iterable $collection): mixed
$iteratee
mixed
$accumulator
?iterable<mixed>
$collection
Examples
reduce(ary(2, subtract(...)), 0, [1, 2, 3, 4]); // -10
remove($start, $count, $iterable)
Removes items from $iterable starting at $start and containing $count elements.
Parameters
positive-int
$start
positive-int
$count
?iterable<mixed>
$iterable
Examples
remove(2, 3, [1,2,3,4,5,6,7,8]); // [1,2,6,7,8]
resolve($resolvers, $record)
Adds new properties to $record using $resolvers.
Parameters
array<string, callable(array<string, mixed>): mixed>
$resolvers
array<string, mixed>
$record
Examples
$users = [
[ 'name' => 'Steve', 'surname' => 'Jobs' ],
[ 'name' => 'Bill', 'surname' => 'Gates' ]
];
map(
resolve([
'initials' => fn ($r) => $r['name'][0].$r['surname'][0]
]),
$users
);
// [
// [ 'name' => 'Steve', 'surname' => 'Jobs', 'initials' => 'SJ' ],
// [ 'name' => 'Bill', 'surname' => 'Gates', 'initials' => 'BG' ]
// ]
round($precision, $number)
Rounds $number to specified $precision
Parameters
int
$precision
int|float
$number
setPath($path, $value, $record)
Return copy of $record with $path set with $value.
Parameters
(array-key)|array<array-key>|string
$path
mixed
$value
?iterable<mixed>
$record
Examples
$a = [ 'a' => [ [ 'b' => [ 'c' => 3 ] ] ] ];
setPath(['a',0,'b','c'], 113, $a);
// [ 'a' => [ [ 'b' => [ 'c' => 113 ] ] ] ]
slice($start, $end, $collection)
Returns a slice of iterable or string from $start up to, but not including $end.
Template types
T of iterable<mixed>|string
Parameters
int
$start
?int
$end
\T|null
$collection
Examples
$a = ['a','b','c','d','e'];
slice(1, 3, $a); // ['b','c']
slice(1, -2, $a); // ['b','c']
slice(-4, -2, $a); // ['b','c']
slice(2, null, $a); // ['c','d','e']
sort($comparator, $collection)
Sorts $collection using $comparator comparison ($a <=> $b) function.
Parameters
callable(mixed $a, mixed $b): int
$comparator
returns -1|0|1
?iterable<mixed>
$collection
Examples
$diff = fn ($a, $b) => $a - $b;
sort($diff, [4,2,7,5]); // [2, 4, 5, 7]
sortBy($iteratees, $collection)
Sorts $collection in ascending order according to $comparators.
Parameters
array<callable(mixed $value): mixed>
$iteratees
?iterable
$collection
Examples
$users = [
[ 'user' => 'fred', 'age' => 48 ],
[ 'user' => 'barney', 'age' => 36 ],
[ 'user' => 'fred', 'age' => 40 ],
[ 'user' => 'barney', 'age' => 34 ]
];
sortBy([property('user'), property('age')], $users);
// [
// [ 'user' => 'barney', 'age' => 34 ],
// [ 'user' => 'barney', 'age' => 36 ],
// [ 'user' => 'fred', 'age' => 40 ],
// [ 'user' => 'fred', 'age' => 48 ]
// ]
sortWith($comparators, $collection)
Sorts a $collection according to an array of comparison ($a <=> $b) functions.
Parameters
array<callable(mixed $a, mixed $b): int>
$comparators
?iterable<mixed>
$collection
Examples
$people = [
[ 'name' => 'clara', 'age' => 40],
[ 'name' => 'bob', 'age' => 30],
[ 'name' => 'alice', 'age' => 40],
];
sortWith(
[ descend(prop('age')), ascend(prop('name')) ],
$people
);
// alice, clara, bob
split($separator, $s)
Splits string by $separator regular expression.
Parameters
string
$separator
doesn't use /pattern/ delimiters
string
$s
Examples
split('\W+', 'aa bb'); // ['aa', 'bb']
splitAt($index, $arrayOrString)
Splits a given array or string at a given index.
Parameters
positive-int
$index
The index where the array/string is split.
array|string
$arrayOrString
Examples
splitAt(1)([1, 2, 3]); // [[1], [2, 3]]
splitEvery($length, $arrayOrString)
Splits an array or string into slices of the specified length.
Parameters
positive-int
$length
length of slice
array|string
$arrayOrString
Examples
splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); // [[1, 2, 3], [4, 5, 6], [7]]
splitWhen($predicate, $iterable)
Splits an array by predicate.
Parameters
callable(mixed $value, array-key $key, iterable $collection): bool
$predicate
iterable<mixed>
$iterable
Examples
splitWhen(equals(2), [1, 2, 3, 1, 2, 3]); // [[1], [2, 3, 1, 2, 3]]
splitWhenever($predicate, $iterable)
Splits an array into slices on every occurrence of a value.
Parameters
callable(mixed $value): bool
$predicate
that determines where the array is split
?iterable<mixed>
$iterable
Examples
splitWhenever(equals(2), [1, 2, 3, 2, 4, 5, 2, 6, 7]); // [[1], [3], [4, 5], [6, 7]]
startsWith($target, $s)
If string starts with $target.
subtract($a, $b)
sum($collection)
Sums elements in $collection
Parameters
?iterable<mixed>
$collection
Examples
sum([4, 2, 8, 6]); // 20
sumBy($iteratee, $collection)
Sums elements, $iteratee is invoked for each element in $collection to generate the value to be summed.
Parameters
callable(mixed $value): \number
$iteratee
?iterable<mixed>
$collection
Examples
$ns = [[ 'n'=> 4 ], [ 'n'=> 2 ], [ 'n'=> 8 ], [ 'n'=> 6 ]];
sumBy(property('n'), $ns); // 20
T(...$args)
take($n, $collection)
Takes $n first elements from iterable.
Parameters
positive-int
$n
?iterable<mixed>
$collection
Examples
take(2, [1, 2, 3]); // [1, 2]
takeLast($n, $collection)
Returns a slice of iterable with $n elements taken from the end.
Parameters
positive-int
$n
?iterable<mixed>
$collection
Examples
takeRight(2, [1, 2, 3]); // [2, 3]
tap($interceptor, $value)
Calls $interceptor($value) then returns the original $value.
Template types
T of mixed
Parameters
callable(\T $value): void
$interceptor
\T
$value
times($iteratee, $n)
Calls the iteratee $n times, returning an array of the results of each invocation.
Parameters
callable(int $index): mixed
$iteratee
$index begins at `0` and is incremented to `$n - 1`
positive-int
$n
Examples
times(fn($i) => "$i", 3); // ['0', '1', '2']
toLower($s)
Converts string to lower case.
toPairs($record)
Converts a record into an array of [$key, $value].
Returns
iterable<array{array-key, mixed}>
Examples
toPairs(['a' => 1, 'b' => 2, 'c' => 3]); // [['a', 1], ['b', 2], ['c', 3]]
toUpper($s)
Converts string to upper case.
trim($characters, $string)
Strip characters from the beginning and end of a string.
Parameters
string
$characters
that need to be stripped
string
$string
that will be trimmed
Examples
trim(" \t.", "\t\tThese are a few words :) ... "); // These are a few words :)
trimEnd($characters, $string)
Strip characters from the end of a string.
Parameters
string
$characters
that need to be stripped
string
$string
that will be trimmed
trimStart($characters, $string)
Strip characters from the beginning of a string.
Parameters
string
$characters
that need to be stripped
string
$string
that will be trimmed
tryCatch($tryer, $catcher, $value)
Calls $tryer, if it throws, calls $catcher.
Template types
T of mixed
Parameters
callable(\T $value): mixed
$tryer
callable(\Exception $e, \T $value): mixed
$catcher
\T
$value
Examples
tryCatch(fn ($v) => "[$v]", fn ($err, $value) => [$err, $value])('A'); // '[A]'
tryCatch(
fn ($v) => throw new \Exception('Error'),
fn (\Exception $err, $value) => [$err->getMessage(), $value]
)('A'); // ['Error', 'A']
unapply($fn)
Returns fn (...$args) => $fn($args)
Examples
unapply(\json_encode(...))(1,2,3); // '[1,2,3]'
unary($fn)
uniq($collection)
Removes duplicates using ===.
Parameters
?iterable<mixed>
$collection
Examples
uniq([1, 1, 2, '1']); // [1, 2, '1']
uniqBy($iteratee, $collection)
Like uniq but apply $iteratee fist.
Parameters
callable(mixed): mixed
$iteratee
?iterable<mixed>
$collection
Examples
uniqBy(\abs(...))([-1, -5, 2, 10, 1, 2]); // [-1, -5, 2, 10]
uniqWith($predicate, $collection)
Like uniq but uses $predicate to compare elements.
Parameters
callable(mixed $a, mixed $b): bool
$predicate
?iterable<mixed>
$collection
Examples
uniqWith(fn ($a, $b) => $a == $b)([1, '1', 2, 1]); // [1, 2]
unless($predicate, $whenFalse, $value)
Returns $predicate($value) ? $value : $whenFalse($value).
Template types
T of mixed
Parameters
callable(\T): bool
$predicate
callable(\T): mixed
$whenFalse
\T
$value
Examples
$safeInc = unless(\is_null(...), inc(...));
$safeInc(null); // null
$safeInc(1); // 2
useWith($fn, $transformers)
Applies each transformer function to each argument. Returns a new curried functions.
Parameters
callable
$fn
The function to wrap.
callable[]
$transformers
Transformer functions
Examples
$f = useWith(unapply(join(' ')), [toLower(...), toUpper(...)]);
$f('HELLO', 'world!'); // hello WORLD!
values($collection)
Returns an indexed iterable of values in $collection.
Parameters
?iterable<array-key, mixed>
$collection
Examples
values(['a' => 'AA', 'b' => 'BB']); // ['AA', 'BB']
when($predicate, $whenTrue, $value)
Returns $predicate($value) ? $whenTrue($value) : $value.
Template types
T of mixed
Parameters
callable(\T $value): bool
$predicate
callable(\T $value): mixed
$whenTrue
\T
$value
where($spec, $record)
Checks if $record satisfies the spec by invoking the $spec properties with the corresponding properties of $record.
Parameters
array<string, callable(mixed): bool>
$spec
?iterable<string, mixed>
$record
Examples
$a = ['a' => 'A', 'b' => 'B'];
where(['a' => fn ($v) => $v == 'A'], $a); // true
whereAny($spec, $record)
Checks if $record satisfies the spec by invoking the $spec properties with the corresponding properties of $record. Returns true if at least one of the predicates returns true.
Parameters
array<string, callable(mixed): bool>
$spec
?iterable<string, mixed>
$record
Examples
$objects = [
[ 'a' => 2, 'b' => 1 ],
[ 'a' => 1, 'b' => 2 ]
];
$pred = whereAny([
'a' => gt(_, 10),
'b' => lt(_, 2)
]);
filter($pred, $objects); // [[ 'a' => 2, 'b' => 1 ]]
whereEq($spec, $test)
Check if the $test satisfies the $spec.
Parameters
array<string, mixed>
$spec
?iterable<string, mixed>
$test
Examples
$pred = whereEq(['a' => 1, 'b' => 2]);
$pred(['a' => 1])); // false
$pred(['a' => 1, 'b' => 2])); // true
$pred(['a' => 1, 'b' => 2, 'c' => 3])); // true
$pred(['a' => 1, 'b' => 1])); // false
without($values, $collection)
Returns $iterable without $values.
Parameters
mixed[]
$values
?iterable<mixed>
$collection
Examples
without([1, 2], [2, 1, 2, 3]); // [3]
words($pattern, $s)
Splits string into an array of its words.
Parameters
string
$pattern
doesn't use /pattern/ delimiters
string
$s
Examples
words('\w+', 'aa bb cc'); // ['aa', 'bb', 'cc']
zip($a, $b)
Creates a new iterable out of the two supplied by pairing up equally-positioned items from both iterables.
Parameters
iterable<mixed>
$a
iterable<mixed>
$b
Returns
iterable<array{mixed, mixed}>
Examples
$a = ['a', 'b' ];
$aa = ['AA','BB'];
zip($a, $aa); // [ ['a', 'AA'], ['b', 'BB'] ]
zipAll($iterables)
Same as zip but for many iterables.
zipWith($iteratee, $a, $b)
Like zip except that it accepts $iteratee to specify how grouped values should be combined.
Parameters
callable(mixed $a, mixed $b): mixed
$iteratee
iterable<mixed>
$a
iterable<mixed>
$b
Examples
$a = ['a', 'b' ];
$aa = ['AA','BB'];
zipWith(fn ($a,$b) => $a.'='.$b, $a, $aa); // ["a=AA", "b=BB"]