Skip to content

Instantly share code, notes, and snippets.

@mcaskill
Created November 11, 2016 18:15
Show Gist options
  • Select an option

  • Save mcaskill/fce03aee1b430328a59e0671e0ee8976 to your computer and use it in GitHub Desktop.

Select an option

Save mcaskill/fce03aee1b430328a59e0671e0ee8976 to your computer and use it in GitHub Desktop.
PHP : Function composition — 'a(b(c(x)))' or 'c(b(a(x)))'

compose

(PHP 5 >= 5.6)
compose — Compose the given functions into a new one (a(b(c(x)))).

Description

Closure compose( callable ...$fns )

Create and return a new anonymous function that iterates over the function list (the given arguments) when executed.

Similar to sequence(), except the function list is executed in reverse — the last function is executed first.

compose(a, b, c) => a(b(c(x)))

The new function will chain the arguments between every function call and return the final result of the first argument.

Additional arguments can be passed to the composed function. They are applied to each function call but only the first argument is returned in the end.

x = a( b( c( x, y, z ), y, z ), y, z )

Parameters

  • ...$fns — One or more functions to compose.

Return Values

Returns the newly created Closure object.


sequence

(PHP 5 >= 5.6)
sequence — Compose the given functions into a new one (c(b(a(x)))).

Description

Closure sequence( callable ...$fns )

Create and return a new anonymous function that iterates over the function list (the given arguments) when executed.

Similar to compose(), except the function list is executed in the order given.

sequence(a, b, c) => c(b(a(x)))

The new function will chain the arguments between every function call and return the final result of the first argument.

Additional arguments can be passed to the composed function. They are applied to each function call but only the first argument is returned in the end.

x = c( b( a( x, y, z ), y, z ), y, z )

Parameters

  • ...$fns — One or more functions to compose.

Return Values

Returns the newly created Closure object.


Examples

Example #1 compose() example

$number = compose('round', 'floatval');

var_dump($number('72.5')); // float(73)

Example #2 sequence() example

$length = function($text) {
	return strlen($text);
};

$obscure = function($length) {
	return str_repeat("*", $length);
};

$replace = sequence($length, $obscure);

var_dump($replace('password')); // "********"

Example #3 sequence() example

$join = function($x) {
	return implode(' ', $x);
};

$flip = function($a, $b) {
	return [ $b, $a ];
};

$double = sequence($flip, $join);

var_dump($double('world', 'hello')); // "hello world"

Installation

With Composer

$ composer require mcaskill/php-compose-functions
{
	"repositories": [
		{
		  "type": "git",
		  "url": "https://gist.github.com/***.git"
		}
	],
	"require": {
		"mcaskill/php-compose-functions": "dev-master"
	}
}

Without Composer

Why are you not using composer? Download Function.Compose-Sequence.php from the gist and save the file into your project path somewhere.


Based on "Function Composition" by Christopher Pitt and by "Composing Functions in JavaScript" Blake Embrey.

{
"name": "mcaskill/php-compose-functions",
"description": "Compose (`a(b(c(x)))`) or sequence (`c(b(a(x)))`) the given functions into a new one.",
"authors": [
{
"name": "Chauncey McAskill",
"email": "[email protected]",
"homepage": "https://github.com/mcaskill"
}
],
"keywords": [
"function",
"composition"
],
"require": {
"php": ">=5.6.0"
},
"autoload": {
"files": ["Function.Compose-Sequence.php"]
}
}
<?php
/**
* Compose the given functions into a new one (`a(b(c(x)))`).
*
* Similar to {@see sequence()}, except the function list is executed in reverse —
* the last function is executed first.
*
* ```
* compose(a, b, c) => a(b(c(x)))
* ```
*
* The new function will chain the arguments between every function call and
* return the final result of the first argument.
*
* Additional arguments can be passed to the composed function. They are applied
* to each function call but only the first argument is returned in the end.
*
* ```
* x = a( b( c( x, y, z ), y, z ), y, z )
* ```
*
* @param callable ...$fns Variable list of functions to compose.
* @return Closure Returns the newly created Closure object.
*/
function compose(callable ...$fns)
{
/**
* Return a Closure composed of the given functions.
*
* @param mixed ...$args Variable list of arguments to apply.
* @return mixed Returns the final result from chaining the first argument
* between every function call.
*/
return function (...$args) use ($fns) {
$args = func_get_args();
for ($i = count($fns) - 1; $i > -1; $i--) {
$args[0] = $fns[$i](...$args);
}
return $args[0];
};
}
/**
* Compose the given functions into a new one `c(b(a(x)))`.
*
* ```
* sequence(a, b, c) => c(b(a(x)))
* ```
*
* Similar to {@see compose()}, except the function list is executed in the order given.
*
* The new function will chain the arguments between every function call and
* return the final result of the first argument.
*
* Additional arguments can be passed to the composed function. They are applied
* to each function call but only the first argument is returned in the end.
*
* ```
* x = c( b( a( x, y, z ), y, z ), y, z )
* ```
* @param callable ...$fns Variable list of functions to compose.
* @return Closure Returns the newly created Closure object.
*/
function sequence(callable ...$fns)
{
return compose(...array_reverse($fns));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment