Functional Programming
with PHP 7
About me
http://sergiors.com
Don’t worry be happy and follow me ✌
What we will learn?
Functional Programming concepts,
jargons and a lot of beautiful examples
that will be blow your mind.
And where I can use it?
Can I apply it on a daily
basis?
In your data, business logic, etc…
Of course!
https://speakerdeck.com/
marcelgsantos/programacao-funcional-
em-php-saia-da-zona-de-conforto
For a deeper knowledge
Let’s go to the party!
Lambda or
Anonymous function
$foo = function () {
};
Closure
$bar = function () use ($fuzz) {
}
It has access to external scope
Higher-order functions
Takes one or more functions as arguments
and returns a function as its result.
Currying
Currying is converting a single function of n
arguments into n functions with a single
argument each.
f(x, y, z) -> f(x)(y)(z)
function has($x)
{
return function (array $xss) use ($x) {
return isset($xss[$x]);
};
}
$hasName = has('name');
$hasName(['name' => 'Sérgio']); //=> true
$hasName(['yearsOld' => 26]); //=> false
has('lastName')(['lastName' => 'Siqueira']); //=> true
Currying vs Partial
Application
Partial Application,
what?
function has(...$args)
{
return partial(function (array $xss, $x) {
return isset($xss[$x]);
})(...$args);
}
$hasName = has('name');
$hasName(['name' => 'Sérgio']); //=> true
$hasName(['yearsOld' => 26]); //=> false
has('lastName')(['lastName' => 'Siqueira']); //=> true
function has(...$args)
{
return partial(function (array $xss, $x) {
return isset($xss[$x]);
})(...$args);
}
$hasName = has('name');
$hasName(['name' => 'Sérgio']); //=> true
$hasName(['yearsOld' => 26]); //=> false
has('lastName')(['lastName' => 'Siqueira']); //=> true
Tacit programming or
point-free style
function has(...$args)
{
return partial(function (array $xss, $x) {
return isset($xss[$x]);
})(...$args);
}
$hasName = has('name');
$hasName(['name' => 'Sérgio']); //=> true
$hasName(['yearsOld' => 26]); //=> false
has('lastName')(['lastName' => 'Siqueira']); //=> true
function partial(callable $fn, ...$args)
{
$arity = (new ReflectionFunction($fn))
->getNumberOfRequiredParameters();
return isset($args[$arity - 1])
? $fn(...$args)
: function (...$restArgs) use ($fn, $args) {
return partial($fn, ...array_merge($args, $restArgs));
};
}
function partial(callable $fn, ...$args)
{
$arity = (new ReflectionFunction($fn))
->getNumberOfRequiredParameters();
return isset($args[$arity - 1])
? $fn(...$args)
: function (...$restArgs) use ($fn, $args) {
return partial($fn, ...array_merge($args, $restArgs));
};
}
Arity: Number of arguments
a function or operator takes.
function partial(callable $fn, ...$args)
{
$arity = (new ReflectionFunction($fn))
->getNumberOfRequiredParameters();
return isset($args[$arity - 1])
? $fn(...$args)
: function (...$restArgs) use ($fn, $args) {
return partial($fn, ...array_merge($args, $restArgs));
};
}
function partial(callable $fn, ...$args)
{
$arity = (new ReflectionFunction($fn))
->getNumberOfRequiredParameters();
return isset($args[$arity - 1])
? $fn(...$args)
: function (...$restArgs) use ($fn, $args) {
return partial($fn, ...array_merge($args, $restArgs));
};
}
Stop!
Where I use it?
Okey! Let’s go to my
prelude!
Remember, in PHP,
array also is hashmap
public function validate($value, Constraint $constraint)
{
if (empty($value)) {
return $value;
}
$violation = function () use ($value, $constraint) {
$this->context->buildViolation($constraint-
>message)
->setParameter('{{ value }}', $value)
->addViolation();
};
return pipe(
function ($name) {
return preg_replace('/(d|[^sw])/u', '',
$name);
},
function ($name) {
return preg_replace('/[ntr]/', ' ',
$name);
function tail(array $xss)
{
return array_slice($xss, 1);
}
function ifElse(callable $pred)
{
return function (callable $succfn) use ($pred) {
return function (callable $failfn) use ($pred, $succfn) {
return function ($x = null) use ($pred, $succfn, $failfn) {
return $pred($x)
? $succfn($x)
: $failfn($x);
};
};
};
}
function id($id)
{
return $id;
}
function lt($x)
{
return function ($y) use ($x) {
return $x < $y;
};
}
function pipe(callable ...$callbacks)
{
return function ($payload) use ($callbacks) {
$rest = tail(func_get_args());
return array_reduce($callbacks, function ($payload,
$callback) use ($rest) {
return $callback(...array_merge([$payload], $rest));
}, $payload);
};
}
public function validate($value, Constraint $constraint)
{
if (empty($value)) {
return $value;
}
$violation = function () use ($value, $constraint) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $value)
->addViolation();
};
return pipe(
function ($name) {
return preg_replace('/(d|[^sw])/u', '', $name);
},
function ($name) {
return preg_replace('/[ntr]/', ' ', $name);
},
function ($name) {
return preg_replace('/s(?=s)/', ' ', $name);
},
function ($name) {
return preg_match_all('/w{2,}/u', trim($name));
},
ifElse(lt(1))(id)($violation)
)($value);
}
Immutability
$validate = anyPass([
[Validator::phone(), 'validate'],
[Validator::cpf(), 'validate'],
]);
$sanitize = ifElse($validate)
(function ($subject) {
return preg_replace('/D+/', '', $subject);
})
(id);
$user = $this->createQueryBuilder('u')
->where('u.email = :username')
->orWhere("JSONB_HGG(u.data, '{phones, mobile}') = :username")
->orWhere("JSONB_MGG(u.data, 'cpf') = :username")
->setParameter('username', $sanitize($username))
->getQuery()
->getOneOrNullResult();
$throw = function () {
throw new UserNotFoundException();
};
return $user === null
? $throw()
: $user;
function anyPass(array $preds)
{
return function ($x) use ($preds) {
return array_reduce($preds,
function (bool $prev, callable $pred) use ($x) {
return true === $prev
? $prev
: $pred($x);
}, false
);
};
}
$foo = anyPass([
function (array $x) {
return isset($x['mobile']);
},
function (array $x) {
return isset($x['last_name']);
}
]);
$foo(['last_name' => 'Siqueira']); //=> true
$foo(['lastName'] => 'Siqueira'); //=> false
Lack the last argument,
point-free style
$foo = anyPass([
has('mobile'),
has(‘last_name')
]);
$foo(['last_name' => 'Siqueira']); //=> true
$foo(['lastName'] => 'Siqueira'); //=> false
public function getOwner(): UserInterface
{
$data = pipe(filter(has('owner')), head, get)
($this->data['admins'] ?? []);
return new User(
$data('id'),
$data('name'),
new Email($data('email'))
);
}
http://github.com/sergiors/prelude
Thank you! 🍻
Twitter @serg1ors
Github @sergiors
http://sergiors.com

Functional programming with php7