O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.
Being functional in PHP
David de Boer14 May 2016
functional
functions
y = f(x)
f: X → Y
functional programming
functional thinking
functional communication
not languages
Why should you care?
f(x)
Others
PHP
C++
C
Java
– Robert C. Martin
“There is a freight train barreling
down the tracks towards us, with
multi-core emblazoned on it; and
y...
λ
closures
__invoke
2001 2009 2011 2012
array_map
array_filter
callable
Slim
Silex
middlewaresSymfony2
2013 2014 2015 2016
PSR-7
anonymous
classes
foreach
promises
futuresStackPHP
“The limits of my language
mean the limits of my world.”
– Ludwig Wittgenstein
I’m David
/ddeboer
@ddeboer_nl
Erlang: The Movie
Erlang
Concurrent
Passing messages
Fault-tolerant
Let’s begin$ brew install erlang
$ erl
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:
10] [hipe] [...
➊
<?php
$sum = 0;
for ($i = 1; $i <= 5; $i++) {
$sum = $sum + $i;
}
echo $sum;
// 15
-module(math).
-export([sum/1]).
sum(Number) ->
Sum = 0,
Numbers = lists:seq(1, Number),
lists:foreach(
fun(N) ->
Sum = Su...
1> X = 5.
5
2> X.
5
3> X = X * 2.
** exception error: no match of right hand side value 10
4> 5 = 10.
** exception error: ...
1> lists:sum(lists:seq(1, 5)).
15
➋
Imperative<?php
$sum = 0;
for ($i = 1; $i <= 5; $i++) {
$sum = $sum + $i;
}
iteration
keeps
changing
-module(math2).
-export([sum2/1]).
sum2(Number) ->
List = lists:seq(1, Number),
sum2(List, 0).
sum2([], Sum) -> Sum;
sum2(...
Declarative 1<?php
// Declare a function!
function sum($x)
{
if ($x == 0) {
return $x;
}
return $x + sum($x - 1);
}
sum(5)...
Declarative 2<?php
function sum2($number)
{
array_sum(range(1, $number));
}
echo sum2(5);
// yuuuup, 15 again
functionfunc...
Some history
Church Von Neumann
declarative imperative
A lot of our code is about the
hardware it runs on
But programmers should worry

about the conceptual problem domain
Recursion-module(math).
-export([fac/1]).
fac(0) -> 1;
fac(N) -> N * fac(N - 1).
1> math:fac(9).
362880
Recursion fail-module(math).
-export([fac/1]).
fac(0) -> 1;
fac(N) -> N * fac(N - 1).
%%fac(9) = 9 * fac(9 - 1)
%% = 9 * 8...
Tail recursion-module(math).
-export([tail_fac/1]).
tail_fac(N) -> tail_fac(N, 1).
tail_fac(0, Acc) -> Acc;
tail_fac(N, Ac...
➌
$object->setFoo(5);
$value = $object->getFoo();
no
return
value
no input
value
$object->setFoo(5);
$value = $object->getFoo();
$object->setFoo('Change of state!');
$value = $object->getFoo();
no
return...
No side-effects
A pure function
does not rely on data outside itself
does not change data outside itself
Object orientation
Solve problems with objects
Objects have internal state
Modify state through methods
With side-effectsclass Todo
{
public $status = 'todo';
}
function finish(Todo $task)
{
$task->status = 'done';
}
$uhoh = ne...
No side-effectsclass Todo
{
public $status = 'todo';
}
function finish(Todo $task)
{
$copy = clone $task;
$copy->status = '...
Some state 

must change
Read/write database
Get user input
Current date and time
Random values (security)
Immutable objects
PSR-7 HTTP messages
Domain value objects
DateTimeImmutable
Service objects
➍
Higher-order functions
Functions are values
so they can be arguments
and return values
$names = ['Billy', 'Bob', 'Thornton'];
$anonymise = anonymise('sha256');
var_dump(array_map($anonymise, $names));
// array...
$names = ['Billy', 'Bob', 'Thornton'];
$anonymise = anonymise('sha256');
var_dump(array_map($anonymise, $names));
// array...
Middleware<?php
use PsrHttpMessageRequestInterface;
function add_header($header, $value)
{
return function (callable $hand...
Middleware<?php
use PsrHttpMessageServerRequestInterface as Request;
use PsrHttpMessageResponseInterface as Response;
$app...
➎
Composition over
inheritance
Service objects<?php
namespace SymfonyComponentSecurityCore;
interface SecurityContextInterface
{
public function getToken...
Service objects<?php
namespace SymfonyComponentSecurityCoreAuthenticationTokenStorage;
interface TokenStorageInterface
{
p...
Single responsibility
taken to its
logical conclusion
You may not need
all those patterns
Take-aways
Reduce and isolate side-effects
Create immutable value objects
Be declarative
More?
Thanks!
https://joind.in/talk/bc26a
@ddeboer_nl
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
Próximos SlideShares
Carregando em…5
×

Being functional in PHP (PHPDay Italy 2016)

1.228 visualizações

Publicada em

Functional programming, though far from new, has gained much traction recently. Functional programming characteristics have started to appear in the PHP world, too. Microframeworks such as Silex and Slim, middleware architectures such as Stack and even standards such as PSR-7 rely on concepts such as lambdas, referential transparency and immutability, all of which come from functional programming. I’ll give you a crash course in Erlang, a pragmatic functional language to make you feel familiar with the functional paradigm. By comparing code samples between Erlang and PHP, you’ll find out how you can employ functional programming in your PHP applications where appropriate. You’ll see that functional programming is nothing to be scared of. On the contrary, understanding its concepts broadens your programming horizon and provides you with valuable solutions to your problems.

Publicada em: Tecnologia
  • Entre para ver os comentários

Being functional in PHP (PHPDay Italy 2016)

  1. 1. Being functional in PHP David de Boer14 May 2016
  2. 2. functional
  3. 3. functions
  4. 4. y = f(x) f: X → Y
  5. 5. functional programming functional thinking functional communication not languages
  6. 6. Why should you care?
  7. 7. f(x) Others PHP C++ C Java
  8. 8. – Robert C. Martin “There is a freight train barreling down the tracks towards us, with multi-core emblazoned on it; and you’d better be ready by the time it gets here.”
  9. 9. λ closures __invoke 2001 2009 2011 2012 array_map array_filter callable Slim Silex middlewaresSymfony2
  10. 10. 2013 2014 2015 2016 PSR-7 anonymous classes foreach promises futuresStackPHP
  11. 11. “The limits of my language mean the limits of my world.” – Ludwig Wittgenstein
  12. 12. I’m David /ddeboer @ddeboer_nl
  13. 13. Erlang: The Movie
  14. 14. Erlang Concurrent Passing messages Fault-tolerant
  15. 15. Let’s begin$ brew install erlang $ erl Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads: 10] [hipe] [kernel-poll:false] [dtrace] Eshell V7.2.1 (abort with ^G) 1> on OS X REPL
  16. 16.
  17. 17. <?php $sum = 0; for ($i = 1; $i <= 5; $i++) { $sum = $sum + $i; } echo $sum; // 15
  18. 18. -module(math). -export([sum/1]). sum(Number) -> Sum = 0, Numbers = lists:seq(1, Number), lists:foreach( fun(N) -> Sum = Sum + N end, Numbers ), Sum. math:sum(5). no return keyword ** exception error: no match of right hand side value 1
  19. 19. 1> X = 5. 5 2> X. 5 3> X = X * 2. ** exception error: no match of right hand side value 10 4> 5 = 10. ** exception error: no match of right hand side value 10 but isn’t looks like assignment
  20. 20. 1> lists:sum(lists:seq(1, 5)). 15
  21. 21.
  22. 22. Imperative<?php $sum = 0; for ($i = 1; $i <= 5; $i++) { $sum = $sum + $i; } iteration keeps changing
  23. 23. -module(math2). -export([sum2/1]). sum2(Number) -> List = lists:seq(1, Number), sum2(List, 0). sum2([], Sum) -> Sum; sum2([H|T], Sum) -> sum2(T, H + Sum). 3> math2:sum(5). 15 empty list separate head from tail recurse pattern matches generate list
  24. 24. Declarative 1<?php // Declare a function! function sum($x) { if ($x == 0) { return $x; } return $x + sum($x - 1); } sum(5); // still 15 $x never changes recursion
  25. 25. Declarative 2<?php function sum2($number) { array_sum(range(1, $number)); } echo sum2(5); // yuuuup, 15 again functionfunction composition
  26. 26. Some history
  27. 27. Church Von Neumann declarative imperative
  28. 28. A lot of our code is about the hardware it runs on But programmers should worry
 about the conceptual problem domain
  29. 29. Recursion-module(math). -export([fac/1]). fac(0) -> 1; fac(N) -> N * fac(N - 1). 1> math:fac(9). 362880
  30. 30. Recursion fail-module(math). -export([fac/1]). fac(0) -> 1; fac(N) -> N * fac(N - 1). %%fac(9) = 9 * fac(9 - 1) %% = 9 * 8 * fac(8 - 1) %% = 9 * 8 * 7 * fac(7 - 1) %% = 9 * 8 * 7 * 6 * fac(6 - 1) %% = 9 * 8 * 7 * 6 * 5 * fac(5 -1) %% = 9 * 8 * 7 * 6 * 5 * 4 * fac(4 - 1) %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * fac(3 - 1) %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * fac(2 - 1) %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 * fac(1 - 1) %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 * 1 %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 %% = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 %% = 9 * 8 * 7 * 6 * 5 * 4 * 6 %% = 9 * 8 * 7 * 6 * 5 * 24 %% = 9 * 8 * 7 * 6 * 120 %% = 9 * 8 * 7 * 720 %% = 9 * 8 * 5040 %% = 9 * 40320 %% = 362880 10 terms in memory
  31. 31. Tail recursion-module(math). -export([tail_fac/1]). tail_fac(N) -> tail_fac(N, 1). tail_fac(0, Acc) -> Acc; tail_fac(N, Acc) -> tail_fac(N - 1, N * Acc). tail_fac(9) = tail_fac(9, 1). tail_fac(9, 1) = tail_fac(9 - 1, 9 * 1). tail_fac(8, 9) = tail_fac(8 - 1, 8 * 9). tail_fac(7, 72) = tail_fac(7 - 1, 7 * 72). tail_fac(6, 504) = tail_fac(6 - 1, 6 * 504). tail_fac(5, 3024) = tail_fac(5 - 1, 5 * 3024). … tail_fac(0, 362880) = 362880 do calculation before recursing
  32. 32.
  33. 33. $object->setFoo(5); $value = $object->getFoo(); no return value no input value
  34. 34. $object->setFoo(5); $value = $object->getFoo(); $object->setFoo('Change of state!'); $value = $object->getFoo(); no return value no input value same argument, different return value
  35. 35. No side-effects A pure function does not rely on data outside itself does not change data outside itself
  36. 36. Object orientation Solve problems with objects Objects have internal state Modify state through methods
  37. 37. With side-effectsclass Todo { public $status = 'todo'; } function finish(Todo $task) { $task->status = 'done'; } $uhoh = new Todo(); $uhoh2 = $uhoh; finish($uhoh); echo $uhoh->status; // done echo $uhoh2->status; // done???
  38. 38. No side-effectsclass Todo { public $status = 'todo'; } function finish(Todo $task) { $copy = clone $task; $copy->status = 'done'; return $copy; } $uhoh = new Todo(); $finished = finish($uhoh); echo $finished->status; // done echo $uhoh->status; // todo cloning is cheap
  39. 39. Some state 
 must change
  40. 40. Read/write database Get user input Current date and time Random values (security)
  41. 41. Immutable objects PSR-7 HTTP messages Domain value objects DateTimeImmutable Service objects
  42. 42.
  43. 43. Higher-order functions Functions are values so they can be arguments and return values
  44. 44. $names = ['Billy', 'Bob', 'Thornton']; $anonymise = anonymise('sha256'); var_dump(array_map($anonymise, $names)); // array(3) { // [0]=> // string(64) "85eea4a0285dcb11cceb68f39df10d1aa132567dec49b980345142f09f4cb05e" // [1]=> // string(64) "cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961" // [2]=> // string(64) "d7034215823c40c12ec0c7aaff96db94a0e3d9b176f68296eb9d4ca7195c958e" // } using PHP built-ins
  45. 45. $names = ['Billy', 'Bob', 'Thornton']; $anonymise = anonymise('sha256'); var_dump(array_map($anonymise, $names)); // array(3) { // [0]=> // string(64) "85eea4a0285dcb11cceb68f39df10d1aa132567dec49b980345142f09f4cb05e" // [1]=> // string(64) "cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961" // [2]=> // string(64) "d7034215823c40c12ec0c7aaff96db94a0e3d9b176f68296eb9d4ca7195c958e" // } function anonymise($algorithm) { return function ($value) use ($algorithm) { return hash($algorithm, $value); }; } higher-order function closure using PHP built-ins function as value function as argument
  46. 46. Middleware<?php use PsrHttpMessageRequestInterface; function add_header($header, $value) { return function (callable $handler) use ($header, $value) { return function ( RequestInterface $request, array $options ) use ($handler, $header, $value) { $request = $request->withHeader($header, $value); return $handler($request, $options); }; }; } $myStack = (new MiddlewareStack()) ->push(add_header('Silly-Header', 'and its value')); call next
 in stack immutable higher-order function
  47. 47. Middleware<?php use PsrHttpMessageServerRequestInterface as Request; use PsrHttpMessageResponseInterface as Response; $app = new SlimApp(); $app->add(function (Request $request, Response $response, callable $next) { $response->getBody()->write('Hey there, '); $response = $next($request, $response); $response->getBody()->write('up?'); return $response; }); $app->get('/', function ($request, $response, $args) { $response->getBody()->write('what’s'); return $response; }); $app->run(); // Hey there, what’s up? stream is not 
 immutable before after
  48. 48.
  49. 49. Composition over inheritance
  50. 50. Service objects<?php namespace SymfonyComponentSecurityCore; interface SecurityContextInterface { public function getToken(); public function isGranted($attributes, $object = null); }
  51. 51. Service objects<?php namespace SymfonyComponentSecurityCoreAuthenticationTokenStorage; interface TokenStorageInterface { public function getToken(); } namespace SymfonyComponentSecurityCoreAuthorization; interface AuthorizationCheckerInterface { public function isGranted($attributes, $object = null); } single function
  52. 52. Single responsibility taken to its logical conclusion
  53. 53. You may not need all those patterns
  54. 54. Take-aways Reduce and isolate side-effects Create immutable value objects Be declarative
  55. 55. More?
  56. 56. Thanks! https://joind.in/talk/bc26a @ddeboer_nl

×