NSPL
Non-Standard PHP Library - functional primitives toolbox and more
Install / Use
/learn @ihor/NSPLREADME
Non-standard PHP library (NSPL)
Non-standard PHP Library (NSPL) is a collection of modules that are meant to solve common day to day routine problems:
- nspl\f - provides functions that act on other functions. Helps to write code in functional programming paradigm
- nspl\op - provides functions that perform standard PHP operations and can be passed as callbacks to higher-order functions. Mimics Python's operator module
- nspl\a - provides missing array functions which also can be applied to traversable sequences
- nspl\a\lazy - provides lazy versions of functions from
\nspl\a - nspl\args - validates function arguments (will be moved into a separate package in version 2.0)
- nspl\ds - provides non-standard data structures and methods to work with them
- nspl\rnd - helps to pick random items from sequences of data
NSPL aims to make code compact and less verbose but still clear and readable. Look at the following example:
// get user ids
$userIds = map(propertyGetter('id'), $users);
// or sort them by age
$sortedByAge = sorted($users, methodCaller('getAge'));
// or check if they all are online
$online = all($users, methodCaller('isOnline'));
// or define new function as composition of the existing ones
$flatMap = compose(rpartial(flatten, 1), map);
In pure PHP it would look like this:
// get user ids
$userIds = array_map(function($user) { return $user->id; }, $users);
// sort them by age, note that the following code modifies the original users array
usort($users, function($user1, $user2) {
return $user1->getAge() - $user2->getAge();
});
// check if they all are online
$online = true;
foreach ($users as $user) {
if (!$user->isOnline()) {
$online = false;
break;
}
}
// define new function as composition of the existing ones
$flatMap = function($function, $list) {
// note the inconsistency in array_map and array_reduce parameters
return array_reduce(array_map($function, $list), 'array_merge', []);
};
You can see more examples in the library reference below or here.
Installation
Using composer
Define the following requirement in your composer.json file:
"require": {
"ihor/nspl": "~1.3"
}
or execute the following in the command line:
composer require ihor/nspl
For the latest version which contains way more functionality require version 2.0.*-dev
Manually
Checkout the code and include autoload.php:
include 'path/to/nspl/autoload.php';
Reference
This is documentation for the dev version 2.0.*-dev which contains the latest changes. For the version 1.3 (latest stable version) documentation click here.
Here I assume that described functions are imported with use function:
use function nspl\a\zip;
$pairs = zip([1, 2, 3], ['a', 'b', 'c']);
If your PHP version is less than 5.6 you should import parent namespace and use functions with the namespace prefix:
use nspl\a;
$pairs = a\zip([1, 2, 3], ['a', 'b', 'c']);
Table of contents
nspl\f
Provides functions that act on other functions. Helps to write code in the functional programming paradigm.
id($value)
Identity function. Returns passed value.
assert(1 === id(1));
apply($function, array $args = [])
Applies given function to arguments and returns the result
assert([1, 3, 5, 7, 9] === apply('range', [1, 10, 2]));
partial($function, $arg1)
Returns new partial function which will behave like $function with predefined left arguments passed to partial
$sum = function($a, $b) { return $a + $b; };
$inc = partial($sum, 1);
rpartial($function, $arg1)
Returns new partial function which will behave like $function with predefined right arguments passed to rpartial
$cube = rpartial('pow', 3);
ppartial($function, array $args)
Returns new partial function which will behave like $function with predefined positional arguments passed to ppartial
$oddNumbers = ppartial('range', array(0 => 1, 2 => 2));
flipped($function)
Returns function which accepts arguments in the reversed order
compose($f, $g)
Returns new function which applies each given function to the result of another from right to left
compose(f, g, h) is the same as f(g(h(x)))
use const \nspl\a\flatten;
use const \nspl\a\map;
use function \nspl\f\compose;
use function \nspl\f\partial;
use function \nspl\f\rpartial;
$flatMap = compose(rpartial(flatten, 1), map);
assert(['hello', 'world', 'foo', 'bar'] === $flatMap(partial('explode', ' '), ['hello world', 'foo bar']));
pipe($input, $function1, $function2)
Passes $input to composition of functions (functions have to be in the reversed order)
use const \nspl\op\sum;
use const \nspl\a\filter;
use const \nspl\a\map;
use const \nspl\a\reduce;
use function \nspl\f\partial;
$isEven = function($x) { return $x % 2 === 0; };
$square = function($x) { return $x * $x; };
// sum of squares of all even numbers less than 20
$sum = pipe(
range(1, 20),
partial(filter, $isEven),
partial(map, $square),
partial(reduce, sum)
);
Tip
You can use chaining to get rid of partials in sequence transformations:
use function \nspl\a\with; $sum = with(range(1, 20)) ->filter($isEven) ->map($square) ->reduce(sum);
curried($function, $withOptionalArgs = false)
Returns a curried version of the function. If you are going to curry a function which reads args with func_get_args() then pass the number of args as the 2nd argument.
If the second argument is true, then curry function with optional args otherwise curry it only with required args. Alternatively, you can pass the exact number of args you want to curry.
uncurried($function)
Returns normal (uncurried) version of a curried function
memoized($function)
Returns memoized $function which returns the cached result when the same inputs occur again
$f = function($arg) {
echo sprintf("Performing heavy calculations with '%s'\n", $arg);
return $arg;
};
$memoized = memoized($f);
echo $memoized('Hello world!') . "\n";
echo $memoized('Hello world!') . "\n";
which outputs
Performing heavy calculations with 'Hello world!'
