Functional Programming in PHP

Functional programming has gained a lot of traction those 3 to 5 last years.
First, there are some success stories around it : Twitter move to Scala,
Whatsapp being written in Erlang. Then we have some new kick-ass languages
like Rust. Finally, it seems the new hype is to create a functional language
compiling to javascript : Elm, Purescript. On a more academic front, there
is also research on new concepts like dependant typing, see Idris for example.

Those are all cool and shiny new toys, but we can benefit from some techniques
without having to learn a new tool, just by applying some principles to our
everyday PHP! But first of all, what exactly is functional programming?

Functional programming

Functional programming is a paradigm as are imperative, logical and OO programming.
The main point is that everything is a function, in the mathematical sense. The
corollary of that is that you cannot have side effects since all outputs depends
solely on the input of the function. It also means you cannot have any mutable state,
once something was computed, it cannot be changed to something else.

This can be cumbersome a time, so a distinction was made between pure functional
languages (like Haskel or Ocaml) and other function languages, Scala for example,
where you can introduce mutable variables or even do plain old Java.

Another issue are input and outputs which are by definition mutable, the “problem”
has been resolved in most functional languages by wrapping them into a Monad, the rest
of this blog post will not talk about that, so I won’t explain this barbaric word,
but feel free to do some research on the internet, it is really interesting.

Despite all those lengthy explanation, functional programming is first and for all
a way of thinking and solving issues than can be used in any languages
. It is
just easier to do in some that are designed for it.

The advantages

Since the output depends solely on the input, reasoning about a function is made a whole lot
easier, you have everything under the eyes, there is no need to keep in mind any kind of
global or shared state, thus reducing complexity a lot.

Testing is made easier, you don’t have to mock a lot of dependencies or create big ass
objects, you just need to pass the arguments your function need.

A functional style also often result in writing small and self-contained functions used
later as building blocks for bigger functionality, resulting in clearly decoupled code
and extended reusability.

A nice little bonus of a pure function is that you can cache its result, this is called
memoization but more about that later.

A perhaps less appealing argument for us, is that calls to pure function can easily be
distributed across threads or even computers because you have the guarantee that the
inputs are enough to perform the computation and that there will be no side effects.
It is simply a matter of combining the results again at the end.

Functional programming in PHP : The basics

Functions in PHP

The first important thing is that functions are, more or less, first class citizen in
the PHP world :

Mapping

Knowing that, we can start playing around with basic functional concepts. For each example,
the “common” way of doing things will be presented first followed by the functional one
.
As it is often the case in functional programming, we will most of the time manipulate an
array.
Applying a function to all elements :

Reducing

“Reduce” an array, often called “fold” in functional languages :

This particular example might not be a good one, but keep in mind that the applied function
can be of any particular complexity, and that you can declare and use it in other places.

It is also important to note that PHP offers an array_sum function for this particular case :

Filtering

Filter an array :

A good example on how you can leverage the array_filter function is given in “PHP The Right Way“.

Some utility functions

In most functional languages and library, you will also find functions that operates on
predicates (a test that return a boolean) and arrays. The most common examples are :

  • first / last which returns the first, respectively last, element of an array matching the predicate
  • any which returns true as soon as one element matches the predicate
  • all which returns true if all elements matches the predicate

Those don’t exists in PHP but you can find various implementations on the github gist I
created for the occasion.

You can use this kind of function in rights management. For example to check if the
connected user has at least one role with a particular set of permission or to verify that you
can apply a particular transformation on all elements in an array :

Once you have created all those little building blocks to manipulate your data, you can
then compose them to perform more complex operations. Sadly PHP don’t propose a compose
function, but you can again find an implementation in the gist linked above.

For example, say I want to do a reverse natural sort. PHP already proposes most of the sort
function in both “direction”, but this is not the case for natsort, we could however easily
achieve our goal with the following :

There would be a lot of others thing to say or show, but I don’t want to overwhelm you too much
and there is already a lot of really interesting resources available on the web :

There is even a book about this exact subject : “Functional Programming in PHP“.
I didn’t had the opportunity to read it as of now, but the recorded talk available is another take
at explaining functional programming with a bit of PHP history at the beginning. I found it a bit
too long, but still interesting.

Memoization

The last thing I want to talk about is memoization or, put in other words, function results
caching.

Remember when we said that the result is solely dependent on the input, now say we have a
computational heavy function that is called multiple times with the same parameters. Knowing
that this is a pure function means you can just cache the result the first time and then simply
return hit the cache. This is exactly the same thing as using caching for web URLs.

You can do that really easily using static local variables in PHP :

You can also generalize this mechanism using a nifty function that will return a memoized version
of any pure function :

You can then simply do the following :

Et voilà! You just built a cached version of a pure function.

Conclusion

Functional programming in PHP is not necessarily this difficult thing we are something lead to believe it is.
You don’t need to learn a brand new language to start applying the principle in your daily work,
you can even start with tiny little steps and take your time to build up your expertise!

In most cases, having a “functional mindset” makes your code easier to reason with and automatically
promotes common best practices like “Single Responsibility Principle” and “Reusability”. You even have a
total absence of side effect for free if you write pure functions!

Someone once said Functional languages enforce what is simply “good code” in other languages.

Also, learning different ways to do things can only open your mind and make you a better developer.

This is why I encourage you to try techniques discussed in this post and why not take the more radical
decision to try one of those obscure pure functional languages that some bearded guy are talking about
in conferences. I can’t promise you that you will fall in love and don’t come back to PHP, but I am sure
that you will learn a lot in the process!

If I could only say one last thing, it would be : “Always strive to learn new things and don’t stay in your comfort zone”.

wow amazing article :) Thank you. I am gonna start to implement this technique on daily basis. It looks like you can save a lot of resources when you do it right.

Hello. Interesting article but your examples contain many and many side effects. IMHO not good FP style.

Hi razor,

Can you please elaborate on the side effects you mean so that I can try to correct them ?

If you are talking about the “first part” of the examples, they are in imperative style so that people can compare both way. Maybe I could make that clearer.

Oh. My fault. I was talking about the “first part” of the examples.

The parameters of array_map in the example are in the wrong order. All those functions take ( array, callback ) as arguments, except array_map, that takes ( callback, array ), because everything is more or less and never thought through in PHP.

Thanks for the great article, though, especially the memoisation part.

Thanks for the feedback Ölbaum, the error is now corrected :) You gotta love PHP for things like that !

Gilles,

I now need to go in and refactor the entirety of my codebases ;) ! In sincerity — will keep this tucked away and apply the concepts going forward. Excellent article and thanks for writing it.

Two minor issues;

The array_filter example is missing a parenthesis; test should read
function($a) { return ($a % 2 === 0); }

It would be nice if you wrapped the link to your gist in an anchor element so we can click it :)

Thanks again!

~ Brice

Hi Brice,

It seems a really made a mess with my examples, there are a lot of mistakes in their ;) Thanks for the feedback it is now fixed !

I also added a link for the Gist.

Glad you enjoyed the article !

Thanks a lot for sharing this insight into functional programming in the PHP world!

The memoization section is really interesting.

My only suggestion would be to change the PHP syntax highlighting to something more friendly to the reader.

Cheers!

This isn’t even scratching the surface of what FP really is…

@Luciano : we are in the process of switching to a new bloging engine with syntax highlighting. Hopefully it will be out soon and readers would enjoy highlighted PHP code :)

@Roman : I still think it is a good start and people ought to begin with something :) I’ll gladly read anything you have to say about the subject !

Totally agree the only one – point in functional programming is the autoloading, sadly it is triggered on calling a class, there are so many functions ouside there which are just inside a class for the sake of the autoloader