Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Functional Programming in PHP - DorsetPHP

Functional Programming in PHP - DorsetPHP

In the PHP world functions are generally sneered at due to their simplicity and perceived as an evil side effect of spaghetti code. This is not necessarily the case however as when functions are combined in a logical manner they can be very powerful.

In fact they can be deployed to great effect in all manner of applications to create advanced and potentially less error prone software. This talk will take the form of a gentle introduction to functional programming concepts in a PHP context.

It will cater to a variety of levels of knowledge. Right from those who have never heard of functional programming to coders who have been practicing aspects for years in other languages (JavaScript!) - perhaps without even knowing.

During my talk you’ll hear some history, functional theory (introduced gently I promise) and of course some practical examples. You definitely do not need to be a mathematician or expert/functional coder to enjoy this session.

https://www.eventbrite.co.uk/e/php-dorset-may-meetup-tickets-10834290655

Simon Holywell

May 12, 2014
Tweet

More Decks by Simon Holywell

Other Decks in Programming

Transcript

  1. WHO? Lead developer Mosaic in Brighton Full service agency @

    on Twitter Treffynnon SimonHolywell.com
  2. 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
  3. 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
  4. A LITTLE BIT OF HISTORY I started with PHP3 Functions

    were the norm Classes merely wrapped them OOP was very poorly understood
  5. EVOLVE Come PHP4 you get better OOP Functions no longer

    in focus They become seen poorer cousins Can't carry context vs. class properties
  6. 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 ' ;
  7. 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
  8. 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
  9. 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 ]
  10. THE SCALE Pure - Haskell Middle ground - Scala and

    Clojure Dabbling - PHP and Python Hopeless - Brainfuck %
  11. 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
  12. LAMBDA CALCULUS Mathematical functions - abstraction Accept functions as parameters

    Return other functions Basis of functional programming
  13. COMBINATORY LOGIC Haskell Curry Combinatory calculus - 1927 Primitive functions

    combined to build others Named after him Currying Haskell
  14. WORLD WAR II Vienna/Göttingen unsafe Great minds move to US

    or UK Turing involved in code breaking
  15. ERICSSON Ericsson Erlang Highly symbolic to improve productivity Lisp and

    Prolog discounted Focused on Reliability Concurrency
  16. COMMERCIAL ADOPTION Domain specific languages (DSL) Type handling Pattern matching

    Fast to build complex parsers Less code = easier to maintain
  17. CASESTUDY Barclays bank Functional Payout Framework Written in Haskell DSL

    for mathematicians Builds trading applications Functional eased scope creap ^
  18. 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 . ' ) ;
  19. 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 a loop!
  20. 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
  21. 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 ;
  22. 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 . ' ) ;
  23. 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 ' )
  24. BENEFITS OF FUNCTIONAL Techniques useful for OOP Abstraction = more

    readable No distracting guff Just the problem solving stuff
  25. ...AND MORE Shorter code = quicker to debug No global

    state to assemble in mind Focus on the hard problems
  26. 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?
  27. 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
  28. SO WHAT ELSE? Easier parallel processing Who's using the other

    cores in your CPU? Not common in PHP - see pthreads
  29. 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 ; } ;
  30. 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 ' ) ; } ;
  31. EXTEND IT - CLOSURE Just like a lambda , 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
  32. 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 ' )
  33. 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
  34. 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
  35. 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
  36. 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
  37. HIGHER ORDER FUNCTIONS Functions that have other functions as Call

    parameters Return values Can be used to form expressions
  38. 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 ) ;
  39. 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 ' )
  40. 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
  41. 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!
  42. SO MUCH MORE... Function composition Tail recursion Function objects New

    language features Functors Applicatives Monads Event driven programming Null handling & more.
  43. EXIT() Functional PHP book Follow @ for tips Simon Holywell

    Follow @ FunctionalPHP FunctionalPHP.com Treffynnon SimonHolywell.com