Last active
December 22, 2017 21:51
-
-
Save masterfermin02/cf345906183ac3a62fae4c5af49ca45b to your computer and use it in GitHub Desktop.
Usando programacion funcional en php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This is a implementantion in PHP of primary application logic for our Functional Programming blog example | |
* See related blog series at: https://masterfermin02.wordpress.com/tag/functional-programming/ | |
* Version: 1.0 | |
*/ | |
// Access the `obj` using the property `prop` | |
function get_prop($obj, $prop) | |
{ | |
if ( is_callable( $prop ) ) { | |
$key = call_user_func( $prop, $obj); | |
} elseif ( is_object( $obj ) && isset( $obj->{ $prop } ) ) { | |
$key = $obj->{ $prop }; | |
} elseif ( isset( $obj[ $prop ] ) ) { | |
$key = $obj[ $prop ]; | |
} else { | |
$key = $prop; | |
} | |
return $key; | |
} | |
function flip($fn) { | |
return function() use($fn){ | |
$args = array_reverse(func_get_args()); | |
return call_user_func_array($fn, $args); | |
}; | |
} | |
function curry_left($callable) | |
{ | |
$outerArguments = func_get_args(); | |
array_shift($outerArguments); | |
return function() use ($callable, $outerArguments) { | |
return call_user_func_array($callable, array_merge($outerArguments, func_get_args())); | |
}; | |
} | |
function curry_right($callable) | |
{ | |
$outerArguments = func_get_args(); | |
array_shift($outerArguments); | |
return function() use ($callable, $outerArguments) { | |
return call_user_func_array($callable, array_merge(func_get_args(), $outerArguments)); | |
}; | |
} | |
// Given a list of objects, return a list of the values | |
// for property 'prop' in each object | |
function pluck($list, $prop) { | |
return call_user_func(mapWith(getWith($prop)),$list); | |
} | |
// Filter `list` using the predicate function `fn` | |
function filter($list, $fn) { | |
return array_filter($list,$fn); | |
} | |
// Returns an object which groups objects in `list` by property `prop`. If | |
// `prop` is a function, will group the objects in list using the string returned | |
// by passing each obj through `prop` function. | |
function group($list, $prop) { | |
return array_reduce($list,function($grouped, $item) use($prop) { | |
$key = get_prop($item,$prop); | |
$grouped[$key][] = $item; | |
return $grouped; | |
}, []); | |
} | |
// Returns a new list by applying the function `fn` to each item | |
// in `list` | |
function map($list, $fn) { | |
return array_map($fn,$list); | |
} | |
function walk($list, $fn){ | |
array_walk($list, $fn); | |
} | |
function reduce($list, $fn) | |
{ | |
return array_reduce($list,$fn); | |
} | |
// Returns a new object which is the result of mapping | |
// each *own* `property` of `obj` through function `fn` | |
function mapObject($obj, $fn) { | |
$keys = is_array($obj) ? array_keys($obj) : get_object_vars($obj); | |
return array_reduce($keys,function($res,$key) use($obj,$fn){ | |
$res[$key] = call_user_func_array( $fn, [$key, get_prop($obj,$key)]); | |
return $res; | |
},[]); | |
} | |
// Return new list as combination of the two lists passed | |
// The second list can be a function which will be passed each item | |
// from the first list and should return an array to combine against for that | |
// item. If either argument is not a list, it will be treated as a list. | |
// | |
// Ex., pair([a,b], [c,d]) => [[a,c],[a,d],[b,c],[b,d]] | |
function pair($list, $listFn) { | |
is_array($list) || ($list = [$list]); | |
(is_callable($listFn) || is_array($listFn)) || ($listFn = [$listFn]); | |
return call_user_func(flatMapWith(function($itemLeft) use($listFn) { | |
return call_user_func(mapWith(function($itemRight) use($itemLeft) { | |
return [$itemLeft, $itemRight]; | |
}),is_callable($listFn) ? call_user_func( $listFn, $itemLeft ) : $listFn); | |
}),$list); | |
} | |
// Sort a list using comparator function `fn`, | |
// returns new array (shallow copy) in sorted order. | |
function _sort($list, $fn) { | |
usort($list, $fn); | |
return $list; | |
} | |
// Return a copy of the array 'list' flattened by one level, ie [[1,2],[3,4]] = [1,2,3,4] | |
function flatten($list) { | |
return array_reduce($list,function($items,$item){ | |
return is_array($item) ? array_merge($items,$item) : $item; | |
},[]); | |
} | |
// Return a flattened list which is the result of passing each | |
// item in `list` thorugh the function `fn` | |
function flatMap($list, $fn) { | |
return flatten(map($list, $fn)); | |
} | |
// Takes a binary comparison function | |
// and returns a version that adhere's to the Array#sort | |
// API of return -1, 0 or 1 for sorting. | |
function comparator($fn) { | |
return function($a,$b) use($fn){ | |
if(call_user_func($fn,$a,$b)) return -1; | |
if(call_user_func($fn,$b,$a)) return 1; | |
return 0; | |
}; | |
} | |
function getWith($fn) | |
{ | |
return curry_right('get_prop',$fn); | |
} | |
function filterWith($fn) | |
{ | |
return curry_right('filter',$fn); | |
} | |
function mapWith($fn) | |
{ | |
return curry_right('map',$fn); | |
} | |
function groupBy($fn) | |
{ | |
return curry_right('group',$fn); | |
} | |
function mapObjectWith($fn) | |
{ | |
return curry_right('mapObject',$fn); | |
} | |
function flatMapWith($fn) | |
{ | |
return curry_right('flatMap',$fn); | |
} | |
function pluckWith($fn) | |
{ | |
return curry_right('pluck',$fn); | |
} | |
function pairWith($fn) | |
{ | |
return curry_right('pair',$fn); | |
} | |
function sortBy($fn) | |
{ | |
return curry_right('_sort',$fn); | |
} | |
function reduceWith($fn) | |
{ | |
return curry_right('reduce',$fn); | |
} | |
function firstWith($fn) | |
{ | |
return curry_right('first',$fn); | |
} | |
// Similar to Ramda's useWith(fn,...) which allows you to supply | |
// a function `fn`, along with one or more transform functions. When | |
// the returned function is called, it will each argument passed to `fn` | |
// using the correlating transform function - if there are more arguments | |
// than transform functions, those arguments will be passed as is. | |
function useWith($fn /*, txfn, ... */) { | |
$transforms = func_get_args(); | |
array_shift($transforms); | |
$_transform = function($args) use($transforms) { | |
return array_map(function($arg,$i) use($transforms) { | |
return $transforms[$i]($arg); | |
},$args,array_keys($args)); | |
}; | |
return function() use($_transform,$transforms,$fn) { | |
$args = func_get_args(); | |
$transformsLen = count($transforms); | |
$targs = array_slice($args,0,$transformsLen); | |
$remaining = array_slice($args,$transformsLen); | |
return call_user_func_array($fn, array_merge(call_user_func($_transform,$targs), $remaining)); | |
}; | |
} | |
// Return the first / last element matching a predicate | |
function first(array $array, $test) { | |
foreach($array as $v) | |
if(call_user_func($test,$v)) | |
return $v; | |
return null; | |
} | |
// Return true if at least one element matches the predicate | |
function any($array, $test) { | |
foreach($array as $v) | |
if(call_user_func( $test,$v)) | |
return true; | |
return false; | |
} | |
// Return true if all elements match the predicate | |
function all($array, $test) { | |
foreach($array as $v) | |
if(! call_user_func( $test,$v)) | |
return false; | |
return true; | |
} | |
function last(array $array, $test) { | |
return first(array_reverse($array), $test); | |
} | |
function compose() { | |
$args = func_get_args(); | |
$fn = array_shift($args); | |
$gn = array_shift($args); | |
$fog = $gn ? function() use($fn,$gn) { return call_user_func($fn,call_user_func_array($gn,func_get_args())); } | |
: $fn; | |
return count($args) > 0 ? call_user_func_array('compose', array_merge([$fog],$args)) : $fog; | |
} | |
function pipeline(){ | |
return flip('compose'); | |
} | |
// Simple comparison for '>=' | |
function greaterThanOrEqual($a, $b) { | |
return $a >= $b; | |
} | |
function greaterThanOrEqualTo($to){ | |
return curry_right('greaterThanOrEqual',$to); | |
} | |
function lessThan($a,$b) { return $a < $b; } | |
function greaterThan($a,$b) { return $a > $b; } | |
function equal($a,$b) { return $a == $b; } | |
function equalTo($to){ return curry_right('equal',$to); } | |
function setVal($a,$b) | |
{ | |
$a = $b; | |
return $a; | |
} | |
function setValTo($to){ | |
return curry_right('setVal',$to); | |
} | |
//$pipeline = flip('compose'); | |
/*function compose(callable ...$functions) | |
{ | |
$initial = array_shift($functions); | |
return array_reduce($functions, function ($f, $g) { | |
return function (...$args) use ($f, $g) { | |
return $f($g(...$args)); | |
}; | |
}, $initial); | |
}*/ | |
/*function pipeline(callable ...$functions) | |
{ | |
return compose(...array_reverse($functions)); | |
}*/ | |
// Right curried versions of the above functions, which | |
// allow us to create partially applied versions of each | |
// and use within a `compose()` or `sequence()` call | |
/*var getWith = rightCurry(get), | |
filterWith = rightCurry(filter), | |
mapWith = rightCurry(map), | |
groupBy = rightCurry(group), | |
mapObjectWith = rightCurry(mapObject), | |
flatMapWith = rightCurry(flatMap), | |
pluckWith = rightCurry(pluck), | |
pairWith = rightCurry(pair), | |
sortBy = rightCurry(sort);*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Archivo usando en el articulo : https://masterfermin02.wordpress.com/2013/01/19/hola/ | |
* author : Fermin Perdomo | |
*/ | |
$data = json_decode('[ | |
{ | |
"id": 1, | |
"value1": 5, | |
"value2": 10 | |
}, | |
{ | |
"id": 2, | |
"value1": 50, | |
"value2": 100 | |
}, | |
{ | |
"id": 1, | |
"value1": 1, | |
"value2": 2 | |
}, | |
{ | |
"id": 2, | |
"value1": 15, | |
"value2": 20 | |
}, | |
{ | |
"id": 3, | |
"value1": 15, | |
"value2": 20 | |
} | |
]'); | |
include 'functional.php'; | |
require 'vendor/autoload.php'; | |
use League\Pipeline\Pipeline; | |
function trace($label){ | |
return function($val) use($label) { | |
echo $label; | |
echo '\n'; | |
print_r($val); | |
return $val; | |
}; | |
} | |
/* | |
* @prop : mixed | |
* return : int; | |
* description : resive prop of the obj as an argument an return an useWith function | |
*/ | |
function sumProp($prop){ | |
return useWith('array_sum', pluckWith($prop)); | |
} | |
function sumGroupRecord($prop,$list) | |
{ | |
return [ | |
'id' => $prop, | |
'value1' => sumProp('value1')($list), | |
'value2' => sumProp('value2')($list) | |
]; | |
} | |
function groupById($list) | |
{ | |
return groupBy(getWith('id'))($list); | |
} | |
$pipeLine = (new Pipeline) | |
->pipe('groupById') | |
->pipe(mapObjectWith('sumGroupRecord')); | |
$finalProcess = $pipeLine->process($data); | |
print_r($finalProcess); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment