A collection of functions and classes to provide some nice functional tools for your projects, with a simple, consistent and well tested api.
Especially useful to build data processing algorithms in a breeze.
Via Composer
$ composer require ibsciss/php-functionnal
Imagine you want to compute the total VAT amount for october:
Instead of doing things like this:
function compute_october_vat() {
$total_vat_amount = 0;
foreach ($invoices as $invoice) {
if ($invoice->due_date->format('m') == '10') {
$total_vat_amount += $invoice->amount * 0.2;
}
}
return $total_vat_amount;
}
Or, if you want to try with map / reduce functions:
function compute_october_vat() {
return array_reduce(
array_map(
function($invoice) { return $invoice->amount * 0.2; },
array_filter( $invoices, function($invoice) { return $invoice->due_date->format('m') == '10'; } )
),
function($x, $y) { return $x + $y; }, 0);
}
You can now use a more fluent api:
function compute_october_vat() {
return Fp\collection($invoices)
->filter( function($invoice) { return $invoice->due_date->format('m') == '10'; }; )
->map( function($invoice) { return $invoice->amount * 0.2; }; )
->add();
}
The compose function give you the ability to create a new functions from existing functions:
compose(f,g,h)(x) == f(g(h(x)))
A practical example:
$plus_one = function($x) { return $x + 1; };
$square = function($x) { return pow($x, 2); };
$plus_one_and_square = Fp\compose($plus_one, $square);
$plus_one_and_square(2) //return 9
Of course you can compose as much functions as you want.
Pipelines functions are useful to apply transformations to collections, Martin Fowler wrote a very good introduction (based on ruby) about it. On the same blog, you'll find another resource to learn how to refactor your too many loops using pipeline.
The map
, filter
and reduce
functions are wrapper around the native php function, to understand why we have made them please see the FAQ.
Apply a function to each item of a collection to create a new array.
//square each item of the collection
Fp\map(
function($x) {
return pow($x, 2); //square function
}, [1,2,3]
); //return [1,4,9,16]
Build an array composed with items that returns true when passed in the given callback.
//return even values from the collection
Fp\filter(
function($x) {
return ($x % 2 == 0);
},
[1,2,3,4]
); //return [2,4]
It makes an accumulation by passing each item to the given callback. The callback returning value is returned for the next call (an init value is provided for the first call).
//sum values of the collection
Fp\reduce(
function($carry, $item) {
return $carray + $item
},
[1,2,3,4],
0
); //return 10
You can chain operations by using the Fp\collection(collection)
function (don't forget to call values()
to get the results):
//squared even values from the given collection
Fp\collection([1,2,3,4])
->filter(
function($x) { return ($x % 2 == 0); }
)
->map(
function($x) { return pow($x, 2); }
)
->values();
With classical pipeline functions, you have to iterate the whole collection for each step of the transformation and create an intermediate collection which is a massive waste in memory usage.
Moreover you can't really extract a step to use it in other contexts which is bad for code reuse.
To tackle these downsides of classic pipeline function, the functional world come with a nice solution: tranducers
.
like map
like filter
Use with single_result
terminal reducer.
return the first element
return the max
Batch result
Create indexed tuples with results
append to an array
immutable appending by merge
to get a scalar result instead of a collection
- To improve api consistency
- To be able to produce transducers if the iterable is omitted
- To be able to consume
Collection
objects.
Please see CHANGELOG for more information what has changed recently.
$ composer test
Please see CONTRIBUTING for details.
If you discover any security related issues, please email :author_email instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.