dev-master
9999999-devFunctional primitives library.
MIT
The Development Requires
Functional primitives library.
Function primitives form a base of function composition allowing for reusable components., (*2)
Library uses semantic versioning, so that you should be able to upgrade supporting version 1. Version 2 will probably support different ways of function composition, using generators, coroutines and other available language constructs. Also, it will take lessons learned from using this library and apply better API. Later major versions will drop support for PHP5.3. The only reason PHP5.3 is supported, is that all of the code will run on PHP5.3 and to widen the amount of users that can develop using the library., (*3)
Library supports PHP5.3. Other versions of PHP are supported allowing for features in other versions., (*4)
You may install this library using composer., (*5)
TODO: Need to add composer configuration., (*6)
This library is inspired by Lars Strojny Functional PHP repository. The differences are that the functions do not check for whether any of the values are correct and will fail if the collection passed is not an array or traversal. You will get a notice or warning and you will need to fix that in your code., (*7)
Validations should happen outside of the function and the functions in this library assume that you are passing correct values as arguments., (*8)
The other change is that the code in this library reuses existing functions as much as possible. The goal is function composition and reducing duplicated code. The best way to do that is to reuse as much code as possible, even if it will have less performance., (*9)
Some of the functions from Laravel repository have been ported to this library. The names will be different and are under the same namespace as the rest of the library., (*10)
There are going to be differences. I'm going off of the documentation web site and not the PHP code. The behavior won't match exactly, but based on the documentation, should at least provide similar behavior., (*11)
The Laravel test suite for the Laravel helpers might be pulled and copied to this library to provide a match, but I don't really think it matters that much to completely match Laravel's function. If you are using Laravel, then you will be using Laravel's functions. This library is for those that don't want to pull the Laravel library, but still want to use similar functions., (*12)
Functions that mutate the collection along with returning data will not be ported. The functions contained in the library may mutate or access data, but not both at the same time. The functions will also return a copy of the collection with the mutation. The original collection must never be mutated by calling any of the below functions., (*13)
To further extend the library Underscore PHP was used as a reference. Some of the function names are different since some of the functionality matches that of functional PHP and Laravel array Helpers., (*14)
TODO: Need to move this to either docs directory or to the web site for documentation., (*15)
Most collection callback will have the element, index and collection passed as arguments., (*16)
$callback = function($element, $index, $collection) { // return after doing something. };
Reduce collection callback will have an additional argument of the current value., (*17)
$callback = function($element, $current, $index, $collection) { // return something with element and current. };
It is not required to have each parameter and it is recommend to only have the parameters., (*18)
Drop elements in collection until callback returns false. This will remove elements from the initial part of the array., (*19)
$values = array(0, 1, 2, 3, 4); $filtered = \Mimic\Functional\dropFirst($values, function($element) { return $element < 2; });
$filtered
would be array(2, 3, 4)
., (*20)
If the array is not sorted, then the above will not give the desired results., (*21)
$values = array(2, 0, 1, 3, 4); $filtered = \Mimic\Functional\dropFirst($values, function($element) { return $element < 2; });
$filtered
would be array(2, 0, 1, 3, 4)
., (*22)
Drop elements in collection after callback returns true. This will remove elements from the rest of the array., (*23)
$values = array(0, 1, 2, 3, 4); $filtered = \Mimic\Functional\dropFirst($values, function($element) { return $element >= 3; });
$filtered
would be array(0, 1, 2)
., (*24)
Each iterates through each element passing to a callback, but nothing is saved and nothing is returned when iteration is completed., (*25)
$values = array(0, 1, 2, 3, 4); \Mimic\Functional\each($values, function($element) { echo $element * $element; }); // Output: 014916
Iterates through a collection checking that every element pass the callback. This is the opposite of none()., (*26)
$callback = function($element) { return $element === 1; }; $true = \Mimic\Functional\every(array(1, 1, 1, 1), $callback); $false = \Mimic\Functional\every(array(1, 2, 1, 1), $callback);
Accepts elements in a collection, when the callback returns true or discards elements when the callback returns false. Opposite of reject(). The select() function exists as an alias for semantics., (*27)
/** @todo finish example(s) */
Retrieves the first element in a collection, if there is no callback., (*28)
$collection = array(1, 1, 4, 2, 3, 4, 5); $result = \Mimic\Functional\first($collection); // $result = 1; // $index = 0; $result = \Mimic\Functional\head($collection); // $result = 1; // $index = 0;
When there is a callback, then that callback is applied and the first element that the callback returns true for is returned., (*29)
$collection = array(1, 1, 4, 2, 3, 4, 5); $callback = function($element, $index, $collection) { return $element === 4; }; $result = \Mimic\Functional\first($collection, callback); // $result = 4; // $index = 2; $result = \Mimic\Functional\head($collection, callback); // $result = 4; // $index = 2;
Returns the first index in an array where the value is matched., (*30)
$index = \Mimic\Functional\firstIndexOf(['this', 'is', 'a', 'test'], 'a'); // $index = 2
TODO: Complete, (*31)
/** @todo finish example(s) */
TODO: Complete, (*32)
/** @todo finish example(s) */
TODO: Complete, (*33)
/** @todo finish example(s) */
Invoke method on class, if the method exists on the class. This can be used for both instance and class methods. It is possible to use this for objects that are mixed and the execution will skip elements that aren't objects or when the element is combined with the method name parameter is not callable., (*34)
The arguments are passed as an array to allow for better composition. This is largely a PHP5.3 limitation. PHP7 or PHP5.6 solutions probably won't require this in the future., (*35)
class Example { public method test() { return func_get_args(); } public static method testStatic() { return func_get_args(); } } $instance = new Example; $collection = array('nothing', $instance, $instance, 'Example', 'Example'); $result = \Mimic\Functional\invoke($collection, 'test'); // $result = array( // null, // array(), // array(), // null, // null, // ); $result = \Mimic\Functional\invoke($collection, 'test', array(1)); // $result = array( // null, // array(1), // array(1), // null, // null, // ); $result = \Mimic\Functional\invoke($collection, 'testStatic'); // $result = array( // null, // null, // null, // array(), // array(), // ); $result = \Mimic\Functional\invoke($collection, 'testStatic', array(1)); // $result = array( // null, // null, // null, // array(1), // array(1), // );
Invoke method on class, only if the result is callable. You can set the default value that will be returned when the given arguments are not callable. The arguments that are passed to the callback are contained in an array., (*36)
class Example { public method test() { return func_get_args(); } public static method testStatic() { return func_get_args(); } } $instance = new Example; $result = \Mimic\Functional\invokeIf($instance, 'test'); // $result = array(); $result = \Mimic\Functional\invokeIf($instance, 'test', array(1)); // $result = array(1); $result = \Mimic\Functional\invokeIf($instance, 'denied', array(1)); // $result = null; $result = \Mimic\Functional\invokeIf($instance, 'denied', array(1), false); // $result = false; $result = \Mimic\Functional\invokeIf('Example', 'testStatic'); // $result = array(); $result = \Mimic\Functional\invokeIf('Example', 'testStatic', array(1)); // $result = array(1); $result = \Mimic\Functional\invokeIf('Example', 'denied', array(1)); // $result = null; $result = \Mimic\Functional\invokeIf('Example', 'denied', array(1), false); // $result = false;
Invoke the first element that is callable and return the result from this callback., (*37)
class Example1 { public method test() { return func_get_args(); } public static method testStatic() { return func_get_args(); } } class Example2 { public method test() { return array('example2->test()'); } public static method testStatic() { return array('example2::testStatic'); } } $collection = array('nothing', new Example1, new Example2, 'Example1', 'Example2'); $result = \Mimic\Functional\invokeFirst($collection, 'test'); // $result = \Mimic\Functional\value(new Example1)->test(); // $result = array(); $result = \Mimic\Functional\invokeFirst($collection, 'test', array(1)); // $result = \Mimic\Functional\value(new Example1)->test(1); // $result = array(1); $result = \Mimic\Functional\invokeFirst($collection, 'testStatic')); // $result = Example1::testStatic(); // $result = array(); $result = \Mimic\Functional\invokeFirst($collection, 'testStatic', array(1)); // $result = Example1::testStatic(1); // $result = array(1);
Invoke the last element that is callable and return the result from this callback., (*38)
class Example1 { public method test() { return func_get_args(); } public static method testStatic() { return func_get_args(); } } class Example2 { public method test() { return array('example2->test()'); } public static method testStatic() { return array('example2::testStatic'); } } $collection = array('nothing', new Example1, new Example2, 'Example1', 'Example2'); $result = \Mimic\Functional\invokeFirst($collection, 'test'); // $result = \Mimic\Functional\value(new Example2)->test(); // $result = array('example2->test()'); $result = \Mimic\Functional\invokeFirst($collection, 'test', array(1)); // $result = \Mimic\Functional\value(new Example2)->test(1); // $result = array('example2->test()'); $result = \Mimic\Functional\invokeFirst($collection, 'testStatic')); // $result = Example2::testStatic(); // $result = array('example2::testStatic'); $result = \Mimic\Functional\invokeFirst($collection, 'testStatic', array(1)); // $result = Example2::testStatic(1); // $result = array('example2::testStatic');
Retrieve the last element of a collection, when there are no callback given., (*39)
$collection = array(1, 1, 4, 2, 3, 4, 5); $result = \Mimic\Functional\last($collection); // $result = 5; // $index = 6; $result = \Mimic\Functional\tail($collection); // $result = 5; // $index = 6;
If there is a callback passed, then it will return the last element that the callback returns true., (*40)
$collection = array(1, 1, 4, 2, 3, 4, 5); $callback = function($element, $index, $collection) { return $element === 4; }; $result = \Mimic\Functional\last($collection, callback); // $result = 4; // $index = 5; $result = \Mimic\Functional\tail($collection, callback); // $result = 4; // $index = 5;
TODO: Complete, (*41)
/** @todo finish example(s) */
Map iterates through each element applying callback to each. The return value is saved and returned in an array., (*42)
$values = array(0, 1, 2, 3, 4); $squares = \Mimic\Functional\map($values, function($element) { return $element * $element; });
$squares
will contain array(0, 1, 4, 9, 16)
., (*43)
Iterates through a collection checking that none of the elements pass the callback. This is the opposite of every()., (*44)
$callback = function($element) { return $element === 1; }; $true = \Mimic\Functional\none(array(2, 2, 2, 2), $callback); $false = \Mimic\Functional\none(array(1, 2, 2, 2), $callback);
TODO: Complete, (*45)
/** @todo finish example(s) */
TODO: Complete, (*46)
/** @todo finish example(s) */
TODO: Complete, (*47)
/** @todo finish example(s) */
Iterates through a collection returning a single value after processing all of the elements. The initial value must also be passed as the second argument., (*48)
$values = array(0, 1, 2, 3, 4); $sum = \Mimic\Functional\reduce($values, 0, function($element, $current) { return $current + $element; });
$sum
will be 10., (*49)
$values = array(0, 1, 2, 3, 4); $sum = \Mimic\Functional\reduce($values, 5, function($element, $current) { return $current + $element; });
$sum
will be 15., (*50)
TODO: Complete, (*51)
/** @todo finish example(s) */
TODO: Complete, (*52)
/** @todo finish example(s) */
This rejects or discards elements when the callback returns true. Opposite of filter() and select()., (*53)
/** @todo finish example(s) */
Alias for filter(). This function works the same as filter(). This exists to be the opposite of reject() in semantics. So if you wish to select on a collection instead of filter the collection, then you may use this function to do so. That way when reading the code, rejecting and selecting are semantically describe the process on a collection., (*54)
/** @todo finish example(s) */
Short will check the callback and break out of the collection once the callback returns true. This is useful, when you need to escape out of the collection after a condition is met., (*55)
You should also see dropFirst()
and dropLast()
for removing elements from a collection., (*56)
$values = array(0, 1, 2, 3, 4); $checkValue = 5; $contains = \Mimic\Functional\reduce($values, true, false, function($element) use ($checkValue) { return $element === $checkValue; });
$contains
is false., (*57)
$values = array(0, 1, 2, 3, 4); $checkValue = 2; $contains = \Mimic\Functional\reduce($values, true, false, function($element) use ($checkValue) { return $element === $checkValue; });
$contains
is true., (*58)
TODO: Complete, (*59)
/** @todo finish example(s) */
TODO: Complete, (*60)
/** @todo finish example(s) */
TODO: Complete, (*61)
/** @todo finish example(s) */
TODO: Complete, (*62)
/** @todo finish example(s) */
Helper functions don't take a callback and provide a simple way to iterate through a collection performing a specialized task and return the result., (*63)
Creates a callback to be used in collection functions that compares the collection element to the compare value. Optionally testing whether the type also matches., (*64)
$value = 1; $checkTypeMatches = true; $callback = \Mimic\Functional\compare($value, $checkTypeMatches); $false = $callback(0); $false = $callback('0'); $true = $callback(1);
If you don't have a strict check, then it will simply compare two values., (*65)
$value = 1; $checkTypeMatches = false; $callback = \Mimic\Functional\compare($value, $checkTypeMatches); $false = $callback(0); $true = $callback(1); $true = $callback('1');
Contains looks for whether the given value exists in the collection., (*66)
$values = array('something', 'else', 'here'); $exists = \Mimic\Functional\contains($values, 'else'); if ($exists) { echo "Else exists in values."; } $exists = \Mimic\Functional\contains($values, 'hello'); if ( ! $exists ) { echo "Hello does not exist in values."; }
You may also use a strict check to ensure that the type matches., (*67)
$values = array(1, 3, '5'); $exists = \Mimic\Functional\contains($values, 3, true); if ($exists) { echo "3 exists in values."; } $exists = \Mimic\Functional\contains($values, 5, true); if ( ! $exists ) { echo "5 integer does not exists in values."; }
False function checks that every value in the array is false. This is useful in combination with map where you evaluate some clause and then use this function for whether every value is identical to false., (*68)
$values = array(1, 3, 5, 7); $evenEvaluation = \Mimic\Functional\map($values, function($element) { return ($element % 2) === 0; }); $allOdd = \Mimic\Functional\false($evenEvaluation); if ($allOdd) { echo "All values are odd."; }
Falsy function checks that every value in the array evaluates to false. Please note that certain values that aren't false, will still evaluate to false., (*69)
$values = array(false, 0, '', null); $allFalsy = \Mimic\Functional\falsy($values); if ($allFalsy) { echo "All values are falsy."; }
Memorization is the process of storing or saving the results of the function call. This caching allows for very quickly returning results that may take a while to process. This should only be used for pure functions or functions that will always return the same output for the given inputs. Doing this for functions that don't have this behavior will fail., (*70)
The closure that is returned by the memoize function has the same definition of the callback that is passed to the function. It simply wraps the callback with the behavior of storing the results and returning the original result value. Given the hashing process, this should only be used when there is still a performance gain even with the hashing. This should be simple to compare. Run performance benchmarks without memoize and run them with memoize. If it is faster to use memoize, then use it. Be aware that additional memory will be consumed with every call that uses different arguments., (*71)
$memoizedCallback = \Mimic\Functional\memoize(function($name) { echo "Function called!\n"; return 'hello '. $name; }); $result = $memoizedCallback('Jacob'); // Output: Function called! // $result = 'hello Jacob'; // Second call $result = $memoizedCallback('Jacob'); // Output: (No output from call) // $result = 'hello Jacob';
It is also possible to clear all of the results by calling `clear() on the returned object., (*72)
$memoizedCallback = \Mimic\Functional\memoize(function($name) { echo "Function called!"; return 'hello '. $name; }); $result = $memoizedCallback('Jacob'); // Output: Function called! // $result = 'hello Jacob'; $memoizedCallback->clear(); $result = $memoizedCallback('Jacob'); // Output: Function called! // $result = 'hello Jacob';
Finally, it is possible to clear the result of a single value by passing the original argument to the clean
method., (*73)
$memoizedCallback = \Mimic\Functional\memoize(function($name) { echo "Function called!"; return 'hello '. $name; }); $result = $memoizedCallback('Jacob'); // Output: Function called! // $result = 'hello Jacob'; $memoizedCallback->clean('Jacob'); $result = $memoizedCallback('Jacob'); // Output: Function called! // $result = 'hello Jacob';
The result of the call when there are no arguments will also be cached. You may also clean the result of invocation without any arguments by calling $memoizedCallback->clean();
or calling clean
method, also without any arguments., (*74)
Warning: At the moment, memorized can not be passed to other functions in the library. This will be fixed before release., (*75)
Negates any boolean value that is given to the callback. The function is meant to be passed as collection callback functions., (*76)
$callback = function($element) { return true; } $negate = \Mimic\Functional\negate($callback); if ( ! $negate(1, null, null) ) { echo "You shall not pass!" }
True function checks that every value in the array is true. This is useful in combination with map where you evaluate some clause and then use this function for whether every value is identical to true., (*77)
$values = array(2, 4, 6, 8); $evenEvaluation = \Mimic\Functional\map($values, function($element) { return ($element % 2) === 0; }); $allEven = \Mimic\Functional\true($evenEvaluation); if ($allEven) { echo "All values are even."; }
Truthy function checks that every value in the array evaluates to true. Please note that certain values that aren't true, will still evaluate to true., (*78)
$values = array(true, 1, -1, '0', array()); $allTruthy = \Mimic\Functional\truthy($values); if ($allTruthy) { echo "All values are truthy."; }
Value returns the given value, unless a callback is given to value, then the result from the callback called with no arguments will be returned., (*79)
$zero = \Mimic\Functional\value(0); $true = \Mimic\Functional\value(true); $true = \Mimic\Functional\value(function() { return true; });
The value function will work with objects. Please be aware that this shortcut does not need to be used with PHP5.4 and later., (*80)
$object = \Mimic\Functional\value(new Type());
With function passes the given value to the callback and returns the result of the callback., (*81)
$callback = function($value) { return ! $value; }; $false = \Mimic\Functional\with(true, $callback); $true = \Mimic\Functional\with(false, $callback);
Functions which take a collection and apply some process to the collection. These functions don't take a callback and are helpers for common math operations for collections containing integers and floats., (*82)
The functions will work with numeric strings, integers and floats. You could also combine the types in the collection., (*83)
Average returns the average using basic PHP operations. This function does not use GMP
or bcmath
extensions. If you need more accurate results, then you will need to use another function., (*84)
$average = \Mimic\Functional\average(array(0, 1, 2, 3, 4));
$average
will be 2
., (*85)
$average = \Mimic\Functional\average(array(1.5, 2.5, 2.5, 2.5, 3.5, 4.5));
$average
will be 2.83333
., (*86)
Difference returns the total of values subtracted from the initial value. The default value is 0
and is optional., (*87)
$total = \Mimic\Functional\difference(array(1, 2, 3, 4, 5));
$total
will be -15
., (*88)
$total = \Mimic\Functional\difference(array(1, 2, 3, 4, 5), 15);
$total
will be 0
., (*89)
Return the maximum numeric value in a collection., (*90)
$max = \Mimic\Functional\maximum(array(1, 2, 3, 4, 5));
$max
will be 5., (*91)
Return the maximum numeric value in a collection., (*92)
$min = \Mimic\Functional\minimum(array(1, 2, 3, 4, 5));
$min
will be 1., (*93)
Product returns the total of values multiplied by the initial value. The default value is 1
and is optional. Passing 0
(zero) will do nothing and the function will not escape when the initial value is zero causing a delay., (*94)
$total = \Mimic\Functional\product(array(1, 2, 3, 4, 5));
$total
will be 120
., (*95)
$total = \Mimic\Functional\product(array(1, 2, 3, 4, 5), 5);
$total
will be 600
., (*96)
$total = \Mimic\Functional\product(array(1, 2, 3, 0, 4, 5), 1); $total = \Mimic\Functional\product(array(1, 2, 3, 4, 5, 0), 1);
$total
will be 0
for both calls. Any 0
value will break the final value and it will always be zero. Do a filter to remove 0
values., (*97)
Quotient returns the total of values divided by the initial value. The default value is 1
and is optional. Passing 0
(zero) will do nothing and the function will not escape when the initial value is zero causing a delay., (*98)
$total = \Mimic\Functional\quotientDivisor(array(5, 10, 100));
$total
will be 50
. The execution will be 5 / 1
, 10 / 5
and finally 100 / 2
for 50
., (*99)
$total = \Mimic\Functional\quotientDivisor(array(2, 4, 10));
$total
will be 5
. The execution will be 2 / 1
, 4 / 2
, and finally 10 / 2
for 5
., (*100)
$total = \Mimic\Functional\quotientDivisor(array(1, 2, 3), 5);
$total
will be 0.3
. The execution will be 1 / 5
, 2 / 0.2
and finally 3 / 10
for 0.3
., (*101)
$total = \Mimic\Functional\quotientDivisor(array(1, 2, 3, 0, 4, 5), 1); $total = \Mimic\Functional\quotientDivisor(array(1, 2, 3, 4, 5, 0), 1);
$total
will be 0
for both calls. Any 0
value will break the final value and it will always be zero. Do a filter to remove 0
values., (*102)
The quotient()
function is more like how language handles operator precedence. These two functions exist for the purposes of which one is how you want to handle the division. The initial value is by default, not used., (*103)
$total = \Mimic\Functional\quotient(array(100, 10, 5));
$total
will be 2
. The execution will be 100 / 10 / 5
which is 2
., (*104)
$total = \Mimic\Functional\quotient(array(10, 5), 100);
$total
will be 2
. The execution will be 100 / 10 / 5
which is 2
., (*105)
$total = \Mimic\Functional\quotient(array(1, 2, 3, 0, 4, 5), 100); $total = \Mimic\Functional\quotient(array(1, 2, 3, 4, 5, 0), 100);
The 0
values will be ignored or filtered from the evaluation. So the execution will be 100 / 1 / 2 / 3 / 4 / 5
, which is 0.83333333
., (*106)
Sum returns the total of values added from the initial value. The default value is 0
and is optional., (*107)
$total = \Mimic\Functional\difference(array(1, 2, 3, 4, 5));
$total
will be 15
., (*108)
$total = \Mimic\Functional\difference(array(1, 2, 3, 4, 5), 15);
$total
will be 30
., (*109)
Functional primitives library.
MIT