Slide 1

Slide 1 text

Branislav Bujisic - Platform.sh Introduction to Pragmatic Functional PHP

Slide 2

Slide 2 text

–Saunders Mac Line, Categories for the Working Mathematician “All told, a monad in X is just a monoid in the category of endofunctors of X, with product X replaced by composition of endofunctors and unit set by the identity endofunctor.”

Slide 3

Slide 3 text

Continuous Deployment Cloud Hosting Drupal 7 / Drupal 8 / Front End Product Engineer

Slide 4

Slide 4 text

Bad Accent Included

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Fathers of computing were playing in their laboratories... The goal: 
 a computation model free of human decision making

Slide 9

Slide 9 text

Alan Mathison Turing (1912-1954)

Slide 10

Slide 10 text

Alonzo Church (1903-1995)

Slide 11

Slide 11 text

x result A Function calculation

Slide 12

Slide 12 text

λx.x

Slide 13

Slide 13 text

λx.λy.x2+y2

Slide 14

Slide 14 text

(λx.x)y ͢ y

Slide 15

Slide 15 text

(λx.x)(λx.λy.x2+y2)

Slide 16

Slide 16 text

EVERYTHING is a function, even a boolean value! TRUE := λa.λb.a FALSE := λa.λb.b AND := λp.λq.pqp OR := λp.λq.ppq
 NOT := λp.λa.λb.pba

Slide 17

Slide 17 text

TRUE AND FALSE = ? " TRUE FALSE TRUE " FALSE (λp.λq.pqp) TRUE FALSE p q " (λa.λb.a) FALSE TRUE a b

Slide 18

Slide 18 text

EVERYTHING is a function, even a natural number! 0 := λf.λx.x function zero($f, $x) { return $x;
 } 1 := λf.λx.fx function one($f, $x) { return $f($x);
 } 2 := λf.λx.f(fx) function two($f, $x) { return $f($f($x));
 }

Slide 19

Slide 19 text

1+2 = ? " (λf.λx.f(f(fx)) (λf.λx.fx)(λf.λx.f(fx))

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

John Von Neumann (1903-1957)
 Neumann János

Slide 22

Slide 22 text

The Von Neumann Model Input Device Output Device Memory Central Processing Unit Control Unit Arithmetic / Logic Unit ebp-0x1 ebp-0x2 ... 00001010 00000101 ebp-0x4 ebp-0x3 mov eax, [ebp-0x1] jmp ebp-0x0 {

Slide 23

Slide 23 text

The Machine Language mov eax, [ebp-0x1] mov ebx, [ebp-0x2] loopTop: cmp eax, ebx jle loopDone dec eax jmp loopTop loopDone: ebp esp FFFD ebp-0x1 ebp-0x2 ... 10 5 ebp-0x4 ebp-0x3 FFF7 ... ...

Slide 24

Slide 24 text

Higher-Level Programming Languages 10 I = 10 20 J = 5 30 IF I <= J GOTO 60 40 I = I - 1 50 GOTO 30 60 ... mov eax, [ebp-0x1] mov ebx, [ebp-0x2] loopTop: cmp eax, ebx jle loopDone dec eax jmp loopTop loopDone: compiler

Slide 25

Slide 25 text

Higher-Level Programming Languages mov eax, [ebp-0x1] mov ebx, [ebp-0x2] loopTop: cmp eax, ebx jle loopDone dec eax jmp loopTop loopDone: for ($i = 5; $i <= 10; $i++) { ... } compiler

Slide 26

Slide 26 text

Higher-Level Programming Languages mov eax, [ebp-0x1] mov ebx, [ebp-0x2] loopTop: cmp eax, ebx jle loopDone dec eax jmp loopTop loopDone: compiler MyFancyClass - i: int + myFancyLoop

Slide 27

Slide 27 text

Meanwhile, the academia contuned playing with the lambda calculus...

Slide 28

Slide 28 text

Functional Programming Languages

Slide 29

Slide 29 text

Once set, a variable must not be changed during the runtime. Immutability Basic Concepts of Functional Programming class Immutable
 {
 private $var;
 
 public function __construct($var)
 {
 $this->var = $var;
 }
 
 public function get()
 {
 return $this->var;
 }
 } Pragm atic?

Slide 30

Slide 30 text

Not a requirement but a convenient way to prevent unplanned problems. Static Typing Basic Concepts of Functional Programming function sumOfInts(int ...$ints): int
 {
 return array_sum($ints);
 }

Slide 31

Slide 31 text

A pure function always returns the same result for the given set of parameters. sin() 3.14 0.00 1 0.84 2 0.91 Param Result 1 0.84 2 0.91 3.14 0.00 Referential Transparency Basic Concepts of Functional Programming

Slide 32

Slide 32 text

A pure function never changes a state outside of its scope. Eliminated Side-Effects Basic Concepts of Functional Programming user_save() $user $user

Slide 33

Slide 33 text

A pure function does not depend on external state and relies only on the parameters it was called with. No External Dependencies Basic Concepts of Functional Programming user_load($uid) $user

Slide 34

Slide 34 text

A higher-order function can accept another functions as arguments and return a function. Higher-Order Functions Basic Concepts of Functional Programming array_filter($users, $callback) $callback = function ($user) { return ($user->age >= 18); }; $callback = function ($user) { return ($user->gender == 'f')
 && ($user->age < 13); };

Slide 35

Slide 35 text

A function can be passed as argument to other functions, returned as value from other functions and assigned to variables. First Class Functions Basic Concepts of Functional Programming function area($r) {/*...*/} $area = function($r) {/*...*/} array_map($area, $radiuses);

Slide 36

Slide 36 text

But... Why?! • Testing • Caching • Complexity control • Performance*

Slide 37

Slide 37 text

Testing params result [5, 0] 25 [0, 5] 3 [5, 5] 28 [0, 0] 0 test($myObscureFunction, $table); $myFunction = function(int $a, int $b) { // I don't care about the content of
 // this function. If it is clean,
 // it will always return the same // response for the given params. }

Slide 38

Slide 38 text

Testing function test($function, $table) { foreach ($table as $row) { $params = $row['params']); $expected_result = $row['result'];
 
 $result = call_user_func_array($function, $params);
 if ($result !== $expected_result) { echo "Test failed for parameters "
 . implode(', ', $row['params']); } } }

Slide 39

Slide 39 text

Caching –Phil Carlton. Quoted by Martin Fowler in TwoHardThings "There are only two hard problems in Computer Science: cache invalidation and naming things.

Slide 40

Slide 40 text

Caching Memoization params result [5, 0] 25 [0, 5] 3 [5, 5] 28 [0, 0] 0 memoize($myObscureFunction, $parameters); $myFunction = function(int $a, int $b) { // I don't care about the content of
 // this function. If it is clean,
 // it will always return the same // response for the given params. }

Slide 41

Slide 41 text

Memoization:
 Nuts and Bolts function memoize(callable $func, $params = []) { return call_user_func_array($func, $params); } 
 $result = memoize($somethingTerriblyExpensive, [2, 5]); $somethingTerriblyExpensive = function($a, $b) { // ...
 } 
 static $storage = []; $key = get_class($func) . implode(':', $params); // OMG, BAD!! if (!isset($storage[$key])) { $storage[$key] = call_user_func_array($func, $params); } return $storage[$key];

Slide 42

Slide 42 text

Complexity Control Does not necessarily mean "less code to write"

Slide 43

Slide 43 text

–Neal Ford. Functional Thinking (Sebastopol: O'Reilly, 2014) "I’d rather spend my time at a higher level of abstraction, thinking about ways to solve complex business scenarios, not complicated plumbing problems."

Slide 44

Slide 44 text

Higher level of abstraction means: • Less plumbing problems • More focus on business problems • Easier debugging and refactoring • Less control over every aspect of the program • Performance tradeoffs

Slide 45

Slide 45 text

The Stack Push Pop FFFD FFFE FFFF FFFC FFFB FFFA Addr Value FFF8 FFF9 FFF7 FFF6 Stack Frame ebp esp Junk Junk

Slide 46

Slide 46 text

What else can be abstracted away?

Slide 47

Slide 47 text

Loops are not business logic $collection = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; $result = 0; foreach ($collection as $item) { if ($item % 2 == 0) { $result += $item * $item; } } print $result;

Slide 48

Slide 48 text

Abstract away the loop! $collection = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); print $collection ->filter(function ($x) { return $x % 2 == 0; }) ->map(function ($x) { return $x * $x; }) ->reduce(function($x, $y) { return $x + $y; }); use bbujisic\functional\Collection; composer require bbujisic/functional reduce filter map

Slide 49

Slide 49 text

Design patterns are not a business logic Therefore they should be abstracted away

Slide 50

Slide 50 text

Decorator Pattern Pizza 4.00 Mushrooms +1.00 Mozarella +2.00 Basil +0.50 Mushrooms getPrice() Sellable getPrice() Pizza getPrice() Topping __construct(Sellable)
 getPrice() Mozarella getPrice() Basil getPrice()

Slide 51

Slide 51 text

Decorator Pattern $pizza = new Pizza(); $mushroomPizza = new Mushrooms($pizza); $mushroomMozarellaPizza = new Mozarella($mushroomPizza); //... $mushroomMozarellaBasilPizza ->getPrice(); Mushrooms getPrice() Sellable getPrice() Pizza getPrice() Topping __construct(Sellable)
 getPrice() Mozarella getPrice() Basil getPrice() $badPizza = new Basil( new Mozarella( new Mushrooms ( new Pizza() ) ) );

Slide 52

Slide 52 text

Abstract away the Decorator!
 Use composition instead. $badPizza = compose($mushrooms, $mozarella, $basil); $mushrooms = function($price) {return $price + 1;};
 $mozarella = function($price) {return $price + 2;};
 $basil = function($price) {return $price + .5;}; $badPizzaPrice = $badPizza(4); // 4 == base price // Tripple Mozarella FTW
 $fixBadPizza = compose($badPizza, $mozarella, $mozarella);

Slide 53

Slide 53 text

It's not all lollipops and unicorns function identity($value) { return $value; } function compose(...$functions) { return array_reduce( $functions, function ($chain, $function) { return function ($input) use ($chain, $function) { return $function($chain($input)); }; }, 'identity' ); }

Slide 54

Slide 54 text

Primitives for functional programming in PHP { "require": { "lstrojny/functional-php": "~1.2" } }

Slide 55

Slide 55 text

Composition use function Functional\compose;
 
 $betterPizza = compose( $pizzaDough, $mozarella, $mozarella, $mushrooms, $basil, $tomatoes );

Slide 56

Slide 56 text

Memoization use function Functional\memoize;
 
 $results = memoize( $expensiveFunctionYouWantToCache, [$param1, $param2, $param3] );

Slide 57

Slide 57 text

Operations on traversable objects and arrays use function Functional\every; use function Functional\select; use function Functional\invoke;
 
 if (every($group, function($user) {$user->age > 18}) {
 print "You may enter the bar!"; } $kids = select($group, function($user) {
 $user->age < 12;
 }); invoke($kids, 'goToBed', []); // ...

Slide 58

Slide 58 text

Performance

Slide 59

Slide 59 text

time 0s 0.4s 0.8s 1.2s 1.6s map filter reduce 0.86 1.54 1.27 0.48 1.12 0.72 0.23 0.54 0.58 imperative functional lstrojny/functional-php Tested on OS X, Apache 2.4 and PHP 7.1 10 000 000 operations

Slide 60

Slide 60 text

It is safe to parallelize stateless processes

Slide 61

Slide 61 text

Synchronous monthly invoicing Payment Pending Order Email the user Charge Credit Card Completed Order 1 000 times in a single night,
 1 minute per job (optimistic)
 Total: 16h 40m Issue the invoice

Slide 62

Slide 62 text

Synchronous monthly invoicing Payment Pending Order Email the user Charge Credit Card Completed Order 1 000 times in a single night,
 1 minute per job (optimistic)
 Total: 16h 40m Issue the invoice Invoicing Queue

Slide 63

Slide 63 text

Synchronous monthly invoicing Payment Pending Order Email the user Charge Credit Card Completed Order 1 000 times in a single night,
 1 minute per job (optimistic)
 Total: 16h 40m Invoicing Queue Issue the invoice Issue the invoice Issue the invoice

Slide 64

Slide 64 text

Upload a function Request Response

Slide 65

Slide 65 text

Serverless • Compute Service On Demand • Pay infrastructure only during the execution of functions • AWS Lambda (Java, Python, Node.js, C#)
 Google Cloud Functions (Node.js)
 MS Azure Functions (C#, Node.js)
 IBM Cloud Functions (Node.js, Swift, Java, PHP, Python, any compiled language in Docker) • Execute functions on event or on http request

Slide 66

Slide 66 text

PHP is not a functional language

Slide 67

Slide 67 text

PHP monads?

Slide 68

Slide 68 text

Use functional style of programming together with the object-oriented code

Slide 69

Slide 69 text

And if you are a full-stack developer...

Slide 70

Slide 70 text

FTW const collection = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const result = collection .filter(i => i % 2 === 0) .map(i => i * i) .reduce((x, y) => x + y, 0); console.log(result);

Slide 71

Slide 71 text

Wanna talk about functional programming, platform.sh or even monads? Branislav Bujisic
 [email protected] @bbujisic Thanks!