Slide 1

Slide 1 text

FUNCTIONAL PHP SIMON HOLYWELL 12/02/2014 0

Slide 2

Slide 2 text

WHO? Lead developer Mosaic in Brighton Full service agency @ on Twitter Treffynnon SimonHolywell.com

Slide 3

Slide 3 text

WORK Web apps Obligatory CMS!

Slide 4

Slide 4 text

PROJECTS Maintainer of ssdeep - and extension - geo library for PHP - Node.js bot for GTalk - now defunct :( Idiorm and Paris PECL HHVM Navigator PHP-at-Job-Queue-Wrapper njsbot

Slide 5

Slide 5 text

FUNCTIONS IN PHP Rarely employed Discouraged by PHP's evolution Naming collisions The old name spacing object

Slide 6

Slide 6 text

SIMPLE BEASTS PHP functions are: Easy Contained Unaware of global state Can now be namespaced

Slide 7

Slide 7 text

FUNCTION < ? p h p f u n c t i o n h e l l o ( $ a r g = ' W o r l d ' ) { e c h o _ _ F U N C T I O N _ _ . " $ a r g " ; } h e l l o ( ) ; / / h e l l o W o r l d

Slide 8

Slide 8 text

A LITTLE BIT OF HISTORY I started with PHP3 Functions were the norm Classes merely wrapped them OOP was very poorly understood

Slide 9

Slide 9 text

DRY Most mashed code with HTML Functions promoted code reuse HTML then had functions in it!

Slide 10

Slide 10 text

EVOLVE Come PHP4 you get better OOP Functions no longer in focus They become seen poorer cousins Can't carry context vs. class properties

Slide 11

Slide 11 text

PHP5 Functions are still marginalised Still seen as spaghetti The bad way

Slide 12

Slide 12 text

PHP5.3+ Proper anonymous functions We get closures!

Slide 13

Slide 13 text

THE BASICS ARE IN PLACE ¡Functional is possible!

Slide 14

Slide 14 text

JUST WHAT IS FUNCTIONAL? Programming without assignment Stateless Pure

Slide 15

Slide 15 text

WITHOUT ASSIGNMENT... Say goodbye to $ v a r = ' v a l u e ' ; $ C l a s s I n s t a n c e - > p r o p e r t y = ' v a l u e ' ;

Slide 16

Slide 16 text

STATELESS AND PURE No: Globals Side effects Incrementors/accumulators For, while or foreach loops

Slide 17

Slide 17 text

PASSING VALUES From function to function as Arguments Return values

Slide 18

Slide 18 text

10 How would you sum all the integers from one to ten?

Slide 19

Slide 19 text

IMPERATIVE WAY < ? p h p $ s u m = 0 ; f o r ( $ i = 1 ; $ i < = 1 0 ; $ i + + ) { $ s u m + = $ i ; } / / $ s u m = 5 5

Slide 20

Slide 20 text

FUNCTIONAL WAY < ? p h p a r r a y _ s u m ( r a n g e ( 1 , 1 0 ) ) ; More descriptive Removes state ($ s u m ) Reusable components

Slide 21

Slide 21 text

LIKE WELL-DESIGNED OOP Encapsulated Broken down into small chunks Reusable

Slide 22

Slide 22 text

CAN IT BE NEATER? < ? p h p a r r a y _ s u m ( r a n g e ( 1 , 1 0 ) ) ; Lua - s = 0 ; f o r i = 1 , 1 0 d o s = s + i e n d Erlang - l i s t s : s u m ( l i s t s : s e q ( 1 , 1 0 ) ) . Clojure - ( r e d u c e + ( r a n g e ( i n c 1 0 ) ) ) Ruby - ( 1 . . 1 0 ) . i n j e c t ( 0 ) { | s , i | s + i } Python - s u m ( r a n g e ( 1 , 1 0 + 1 ) ) F# - L i s t . s u m [ 1 . . 1 0 ] Scala - ( 1 t o 1 0 ) . s u m Haskell - s u m [ 1 . . 1 0 ]

Slide 23

Slide 23 text

THE SCALE Pure - Haskell Middle ground - Scala and Clojure Dabbling - PHP and Python Hopeless - Brainfuck %

Slide 24

Slide 24 text

HISTORY Vienna Circle - 1920s Philosophers Logic Can be defined apart from content Unless experienced or observed = worthless M! = ethics, metaphysics, religion and aesthetics

Slide 25

Slide 25 text

KURT GÖDEL Attended Vienna Circle Ultimately disproved manifesto Incompleteness theorem - 1931 Some truths cannot be proven

Slide 26

Slide 26 text

FUNCTIONAL HISTORY Kurt Gödel - recursively calculated functions - 1930s Haskell Curry - combinatory logic - 1927 Alan Turing - machines calculating from inputs - 1936 Alonzo Church - lambda calculus - 1930s

Slide 27

Slide 27 text

LAMBDA CALCULUS Mathematical functions - abstraction Accept functions as parameters Return other functions Basis of functional programming

Slide 28

Slide 28 text

COMBINATORY LOGIC Haskell Curry Combinatory calculus - 1927 Primitive functions combined to build others Named after him Currying Haskell

Slide 29

Slide 29 text

WORLD WAR II Vienna/Göttingen unsafe Great minds move to US or UK Turing involved in code breaking

Slide 30

Slide 30 text

ACADEMIC Little activity 'til late 1950s

Slide 31

Slide 31 text

LISP 1958 Jon McCarthy MIT Became the standard for AI

Slide 32

Slide 32 text

MOMENTUM Some advances Still mostly academic Imperative programming the norm

Slide 33

Slide 33 text

TELEPHONES Fault tolerant system Erlang by Ericsson 1980s

Slide 34

Slide 34 text

ERICSSON Ericsson Erlang Highly symbolic to improve productivity Lisp and Prolog discounted Focused on Reliability Concurrency

Slide 35

Slide 35 text

HASKELL Formed by committee Pure functional language

Slide 36

Slide 36 text

COMMERCIAL ADOPTION Domain specific languages (DSL) Type handling Pattern matching Fast to build complex parsers Less code = easier to maintain

Slide 37

Slide 37 text

CASESTUDY Barclays bank Functional Payout Framework Written in Haskell DSL for mathematicians Builds trading applications Functional eased scope creap ^

Slide 38

Slide 38 text

NONE SHALL PASS! < ? p h p $ a l l o w a b l e _ i p s = a r r a y ( ' 1 9 2 . 1 6 8 . 0 . ' , ' 8 . 8 . 8 . 8 ' , ) ; a r r a y _ f i l t e r ( $ a l l o w a b l e _ i p s , f u n c t i o n ( $ i p ) { r e t u r n $ i p = = s u b s t r ( $ _ S E R V E R [ ' R E M O T E _ A D D R ' ] , 0 , s t r l e n ( $ i p ) ) ; } ) ? : d i e ( ' D e n i e d . ' ) ;

Slide 39

Slide 39 text

ARRAY_FILTER() < ? p h p a r r a y _ f i l t e r ( $ a l l o w a b l e _ i p s , f u n c t i o n ( $ i p ) { Takes a list and predicate "Removes" items when predicate fails λ or anonymous function And hey, it's not a loop!

Slide 40

Slide 40 text

THA PREDICATE < ? p h p f u n c t i o n ( $ i p ) { r e t u r n $ i p = = s u b s t r ( $ _ S E R V E R [ ' R E M O T E _ A D D R ' ] , 0 , s t r l e n ( $ i p ) ) ; } IP v.4 addresses Chops user IP to same length as allowable ($ i p ) Compares result for equality

Slide 41

Slide 41 text

KILLER CONDITION < ? p h p ? : d i e ( ' D e n i e d . ' ) ; Empty arrays == false Terminates application Ternary shortcut < ? p h p e x p r 1 ? e x p r 2 : e x p r 3 ; e x p r 1 ? : e x p r 3 ;

Slide 42

Slide 42 text

WHAT SAY THE BLACK KNIGHT? < ? p h p / / $ _ S E R V E R [ ' R E M O T E _ A D D R ' ] = ' 1 9 2 . 1 6 8 . ' $ a l l o w a b l e _ i p s = a r r a y ( ' 1 9 2 . 1 6 8 . 0 . ' , ' 8 . 8 . 8 . 8 ' , ) ; a r r a y _ f i l t e r ( $ a l l o w a b l e _ i p s , f u n c t i o n ( $ i p ) { r e t u r n $ i p = = s u b s t r ( $ _ S E R V E R [ ' R E M O T E _ A D D R ' ] , 0 , s t r l e n ( $ i p ) ) ; } ) ? : d i e ( ' D e n i e d . ' ) ;

Slide 43

Slide 43 text

BONUS: ARRAY CLEANER a r r a y _ f i l t e r ( ) without a predicate Entries == false dropped false == "" == 0 == array() == null == '0' == 0.0 < ? p h p a r r a y _ f i l t e r ( a r r a y ( ' ' , ' s ' , 0 ) ) ; / / a r r a y ( ' s ' )

Slide 44

Slide 44 text

BENEFITS OF FUNCTIONAL Techniques useful for OOP Abstraction = more readable No distracting guff Just the problem solving stuff

Slide 45

Slide 45 text

...AND MORE Shorter code = quicker to debug No global state to assemble in mind Focus on the hard problems

Slide 46

Slide 46 text

HEY! WAIT THERE'S STILL MORE Testing is easier No globals again Values are final

Slide 47

Slide 47 text

REFERENTIAL TRANSPARENCY Replace any function with it's return value Algorithm still works! < ? p h p a r r a y _ s u m ( a r r a y ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 ) ) ; / / I s s t i l l 5 5 ! Can you do that to a for loop?

Slide 48

Slide 48 text

NO! < ? p h p $ s u m = 0 ; f o r ( $ i = 1 ; $ i < = 1 0 ; $ i + + ) { $ s u m + = $ i ; } / / $ s u m = 5 5 Closest: < ? p h p $ s u m = 0 ; $ s u m + = 1 ; $ s u m + = 2 ; . . . $ s u m + = 1 0 ; / / $ s u m = 5 5

Slide 49

Slide 49 text

SO WHAT ELSE? Easier parallel processing Who's using the other cores in your CPU? Not common in PHP - see pthreads

Slide 50

Slide 50 text

IF PHP WERE REALLY FUNCTIONAL Machine optimisation of code Lazy-evaluation Hot code deployment (Erlang!) %

Slide 51

Slide 51 text

STEP BACK - Λ λ lambda function anonymous function < ? p h p $ f u n c _ n a m e = f u n c t i o n ( $ p a r a m ) { r e t u r n $ p a r a m ; } ;

Slide 52

Slide 52 text

SHOULD BE FAMILIAR < ? p h p s p l _ a u t o l o a d _ r e g i s t e r ( f u n c t i o n ( $ c l a s s ) { i n c l u d e ' c l a s s e s / ' . $ c l a s s . ' . c l a s s . p h p ' ; } ) ; If not - how about in JS: b u t t o n . o n c l i c k = f u n c t i o n ( ) { a l e r t ( ' L a m b d a ' ) ; } ;

Slide 53

Slide 53 text

EXTEND IT - CLOSURE Just like a lambda But, with context/data ($ v a l u e ) < ? p h p $ v a l u e = 5 ; $ f u n c _ n a m e = f u n c t i o n ( $ p a r a m ) u s e ( $ v a l u e ) { r e t u r n $ p a r a m + $ v a l u e ; } ; e c h o $ f u n c _ n a m e ( 3 ) ; / / 8 Vars can be other closures or lambdas too No aliasing unfortunately

Slide 54

Slide 54 text

MAP a r r a y _ m a p ( ) Applies function to each element Returns new array with adjusted elements < ? p h p a r r a y _ m a p ( f u n c t i o n ( $ v ) { r e t u r n s t r t o u p p e r ( + + $ v ) ; } , $ a r r a y ) ; a r r a y ( ' o ' , ' g ' , ' o ' ) becomes a r r a y ( ' P ' , ' H ' , ' P ' )

Slide 55

Slide 55 text

SOCHI MAP IT 1st

Slide 56

Slide 56 text

APPLIED BY A MAP 2nd

Slide 57

Slide 57 text

MORE MAPPING! 3rd

Slide 58

Slide 58 text

REDUCE a r r a y _ r e d u c e ( ) Fold array down to one value Applies function to each element < ? p h p a r r a y _ r e d u c e ( $ a r r a y , f u n c t i o n ( $ r e s u l t , $ v ) { r e t u r n $ r e s u l t . = $ v ; } ) ; a r r a y ( ' o ' , ' g ' , ' o ' ) becomes o g o

Slide 59

Slide 59 text

REDUCE FIGURES 9 + 6.10 + 7.62 + 6.98 ...

Slide 60

Slide 60 text

FOLDING SCORES 15.10 + 7.62 + 6.98 ...

Slide 61

Slide 61 text

DISAPPOINTMENT 63.10

Slide 62

Slide 62 text

MAP AND REDUCE Combined to great effect < ? p h p $ a = a r r a y ( ' o ' , ' g ' , ' o ' ) ; a r r a y _ r e d u c e ( a r r a y _ m a p ( f u n c t i o n ( $ v ) { r e t u r n s t r t o u p p e r ( + + $ v ) ; } , $ a ) , f u n c t i o n ( $ r e s u l t , $ v ) { r e t u r n $ r e s u l t . = $ v ; } ) ; / / P H P

Slide 63

Slide 63 text

RECURSION Just like the meaning of PHP A function that calls itself Directly or Indirectly Can be used for loops Loose or forgotten condition = blown stack

Slide 64

Slide 64 text

HEADS OR TAILS PHP = heads < ? p h p f u n c t i o n h e a d _ s u m ( $ x ) { r e t u r n ( $ x = = 1 ) ? $ x : $ x + h e a d _ s u m ( $ x - 1 ) ; } h e a d _ s u m ( 1 0 ) ; / / 5 5 Other languages have optimised tails

Slide 65

Slide 65 text

HIGHER ORDER FUNCTIONS Functions that have other functions as Call parameters Return values Can be used to form expressions

Slide 66

Slide 66 text

HIGHER EXAMPLE < ? p h p $ d a t a = a r r a y ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 ) ; f u n c t i o n g e t _ a l g o r i t h m ( $ r a n d _ s e e d _ f n c ) { r e t u r n ( o d d _ e v e n ( $ r a n d _ s e e d _ f n c ( ) ) ) ? f u n c t i o n ( $ v a l u e ) { r e t u r n $ v a l u e * $ v a l u e ; } : f u n c t i o n ( $ v a l u e ) u s e ( $ r a n d _ s e e d _ f n c ) { r e t u r n ( $ v a l u e * $ v a l u e / $ r a n d _ s e e d _ f n c ( ) ) + 1 0 ; } ; } f u n c t i o n o d d _ e v e n ( $ v a l u e ) { r e t u r n ( $ v a l u e % 2 = = = 0 ) ; } $ r a n d _ s e e d _ f n c = f u n c t i o n ( ) { r e t u r n r a n d ( ) ; } ; $ r e s u l t s = a r r a y _ m a p ( g e t _ a l g o r i t h m ( $ r a n d _ s e e d _ f n c ) , $ d a t a ) ;

Slide 67

Slide 67 text

PARTIAL FUNCTION APPLICATION Essentially set defaults < ? p h p $ f i r s t _ c h a r = f u n c t i o n ( $ s t r i n g ) { r e t u r n s u b s t r ( $ s t r i n g , 0 , 1 ) ; } ; Works nicely with a r r a y _ m a p ( ) < ? p h p a r r a y _ m a p ( $ f i r s t _ c h a r , a r r a y ( ' f o o ' , ' b a r ' , ' b a z ' ) ) ; / / a r r a y ( ' f ' , ' b ' , ' b ' )

Slide 68

Slide 68 text

CURRYING Each parameter becomes a function More flexible PFA < ? p h p $ f i r s t _ c h a r = f u n c t i o n ( $ s t a r t ) { r e t u r n f u n c t i o n ( $ l e n g t h ) u s e ( $ s t a r t ) { r e t u r n f u n c t i o n ( $ s t r i n g ) u s e ( $ s t a r t , $ l e n g t h ) { r e t u r n s u b s t r ( $ s t r i n g , $ s t a r t , $ l e n g t h ) ; } ; } ; } ; $ a = $ f i r s t _ c h a r ( 0 ) ; $ b = $ a ( 1 ) ; $ b ( ' f o o ' ) ; / / f $ c = $ a ( 2 ) ; $ c ( ' f o o ' ) ; / / f o

Slide 69

Slide 69 text

MEMOIZATION Function local cache < ? p h p f u n c t i o n d e m o ( ) { s t a t i c $ _ c ; i f ( i s _ n u l l ( $ _ c ) ) { $ _ c = g e t _ s o m e _ e x p e n s i v e _ o p e r a t i o n ( ) ; } r e t u r n $ _ c ; } Handy in class methods too!

Slide 70

Slide 70 text

WHEN TO USE FUNCTIONAL? Practice Innate understanding Turing complete methodology

Slide 71

Slide 71 text

SO MUCH MORE... Function composition Tail recursion Function objects New language features Functors Applicatives Monads Event driven programming Null handling & more.

Slide 72

Slide 72 text

EXIT() Functional PHP Follow @ for tips Simon Holywell Follow @ FunctionalPHP FunctionalPHP.com Treffynnon SimonHolywell.com