12 min read

This article by Gilles Crettenand, author of the book Functional PHP, covers some of the concepts explained in book in a concise manner. We will look at the following:

  • Declarative programming
  • Functions
  • Recursion
  • Composing functions
  • Benefits of functional programming

(For more resources related to this topic, see here.)

Functional programming has gained a lot of traction in the last few years. Various big tech companies started using functional languages, for example:

  • Twitter on Scala (http://www.artima.com/scalazine/articles/twitter_on_scala.html)
  • WhatsApp being written in Erlang (http://www.fastcompany.com/3026758/inside-erlang-the-rare-programming-language-behind-whatsapps-success)
  • Facebook using Haskell (https://code.facebook.com/posts/302060973291128/open-sourcing-haxl-a-library-for-haskell/1)

There is some really wonderful and successful work done on functional languages that compile to JavaScript—the Elm and PureScript languages to name a few. There are efforts to create new languages that either extend or compile to some more traditional languages, such as Hy and Coconut for Python.

Even Apple’s new language for iOS development, Swift, has multiple concepts from functional programming integrated into its core.

However, this article is not about using a new language or learning a whole new technology, it is about benefiting from functional techniques without having to change our whole stack. By just applying some principles to our everyday PHP, we can greatly improve the quality of our life and code.

Declarative programming

Functional programming is also sometimes called declarative programming in contrast to imperative programming. This languages are called programming paradigms. Object-oriented programming is also a paradigm, but it is the one that is strongly tied to the imperative programming.

Instead of explaining the difference at length, let’s demonstrate with an example. First an imperative programming using PHP:

<?php

function getPrices(array $products) {

// let's assume the $products parameter is an array of products.

$prices = [];

foreach($products as $p) {

   if($p->stock > 0) {

     $prices[] = $p->price;

   }

}

return $prices;

}

Now let’s see how you can do the same with SQL which, among other things, is a declarative language:

SELECT price FROM products WHERE stock > 0;

Notice the difference? In the first example, you tell the computer what to do step by step, taking care of storing intermediary results yourself. In the second example, you only describe what you want and it will then be the role of the database engine to return the results.

In a way, functional programming looks a lot more like SQL than the PHP code we just saw.

Functions

Functional programming, as it names suggests, revolves around functions. In order to apply functional techniques effectively, a language must support functions as a first-class citizen or first functions.

This means that functions are considered like any other value. They can be created and passed around as parameters to other functions and they can be used as return values. Luckily, PHP is such a language, you can create functions at will, pass them around as parameters, and even return them.

Another fundamental concept is the idea of a pure function or, in other words, functions that only use their input to produce a result. This means that you cannot use any kind of external or internal state to perform your computation.

Another way to look at this is from the angle of dependencies. All of the dependencies of your functions need to be clearly declared in the signature. This helps a lot when someone tries to understand how and what your function is doing.

Higher-order functions

PHP functions can take functions as parameters and return functions as return values. A function that does either of those is called a higher-order function. It is as simple as that. There are a few of those that are commonly used in any functional code base.

Map

The map, or array_map, method in PHP is a higher order function that applies a given callback to all the elements of a collection. The return value is a collection in the same order. A simple example is as follows:

<?php

function square(int $x): int

{

return $x * $x;

}

$squared = array_map('square', [1, 2, 3, 4]);

/* $squared contains [1, 4, 9, 16] */

Filter

The filter, or array_filter, method in PHP is a higher order function that keeps only certain elements of a collection based on a Boolean predicate. The return value is a collection that will only contain elements returning true for the predicate function. A simple example is as follows:

<?php

function odd(int $a): bool

{

return $a % 2 === 1;

}

$filtered = array_filter([1, 2, 3, 4, 5, 6], 'odd');

/* $filtered contains [1, 3, 5] */

Fold or reduce

Folding refers to a process where you reduce a collection to a return value using a combining function. Depending on the language, this operation can have multiple names—fold, reduce, accumulate, aggregate, or compress. As with other functions related to arrays, the PHP version is the array_reduce function.

You may be familiar with the array_sum function, which calculates the sum of all the values in an array. This is in fact a fold and can be easily written using the array_reduce function:

<?php

function sum(int $carry, int $i): int

{

return $carry + $i;

}

$summed = array_reduce([1, 2, 3, 4], 'sum', 0);

/* $summed contains 10 */

You don’t necessarily need to use the elements to produce a value. You could, for example, implement a naive replacement for the in_array method using fold:

<?php

function in_array2(string $needle, array $haystack): bool

{

$search = function(bool $contains, string $i) use ($needle) : bool {

   return $needle == $i ? true : $contains;

};

return array_reduce($haystack, $search, false);

}

var_dump(in_array2('two', ['one', 'two', 'three']));

// bool(true)

Recursion

In the academic sense, recursion is the idea of dividing a problem into smaller instances of the same problem. For example, if you need to scan a directory recursively, you first scan the starting directory and then scan its children and grandchildren. Most programming languages support recursion by allowing a function to call itself. This idea is often what is described as being recursion.

Let’s see how we can scan a directory using recursion:

<?php

function searchDirectory($dir, $accumulator = []) {

foreach (scandir($dir) as $path) {

   // Ignore hidden files, current directory and parent directory

   if(strpos($path, '.') === 0) {

     continue;

   }

   $fullPath = $dir.DIRECTORY_SEPARATOR.$path;

   if(is_dir($fullPath)) {

     $accumulator = searchDirectory($path, $accumulator);

   }

   else {

     $accumulator[] = $fullPath;

   }

}

return $accumulator;

}

We start by using the scandir method to obtain all files and directories. Then, if we encounter a child directory, we call the function on it again. Otherwise, we simply add the file to the accumulator. This function is recursive because it calls itself.

You can write this using control structures, but as you don’t know in advance what the depth of your folder hierarchy is, the code will probably be a lot messier and harder to understand.

Trampolines

Each time you call a function, information gets added to the memory. This can be an issue when doing recursion as you only have a limited amount of memory available. Until the last recursive call, memory usage will continue growing and a stack overflow can happen.

The only way we can avoid stack growth is to return a value instead of calling a new function. This value can hold the information that is needed to perform a new function call, which will continue the computation. This also means that we need some cooperation from the caller of the function. This helpful caller is called a trampoline and here is how it works:

  • The trampoline calls our f function
  • Instead of making a recursive call, the f function returns the next call encapsulated inside a data structure with all the arguments
  • The trampoline extracts the information and performs a new call to the f function
  • Repeat the two last steps until the f function returns a real value
  • The trampoline receives a value and returns those to the real caller

If you want to use trampolines in your own project, I invite you to install the following library, which offers some helpers as compared to our crude implementation:

composer require functional-php/trampoline

Here is an example taken from the documentation:

<?php

use FunctionalPHPTrampoline as t;

function factorial($n, $acc = 1) {

return $n <= 1 ? $acc : tbounce('factorial', $n - 1, $n *
$acc);

};

Composing functions

Previously, we discussed the idea of building blocks and small pure functions. But, so far, we haven’t even hinted at how those can be used to build something bigger. What good is a building block if you cannot use it? The answer partly lies in function’s composition.

As it is often the case in functional programming, the concept is borrowed from mathematics. If you have two functions f and g, you can create a third function by composing them. The usual notation in mathematics is (f   g)(x), which is equivalent to calling them one after the other as f(g(x)).

You can compose any two given functions really easily with PHP using a wrapper function. Say, you want to display a title in all caps and only safe HTML characters:

<?php

function safe_title2(string $s)

{

return strtoupper(htmlspecialchars($s));

}

Functional libraries for PHP often come with a helper that can create new functions out of multiple subparts easily. For example, using Lars Strojny’s Functional PHP library, you can write the following:

<?php

$titles4 = array_map(compose('htmlspecialchars', 'strtoupper', 'trim'), $titles);

Partial application

You might want to set some parameters of a function but leave some of them unassigned for later. For example, we might want to create a function that returns an excerpt of a blog post.

The dedicated term for setting such a value is “to bind a parameter” or “bind an argument”. The process itself is called partial application and the new function is set to be partially applied.

The Functional PHP library also comes with helpers to partially apply a function:

<?php

use function Functionalpartial_right;

use function Functionalpartial_left;

use function Functionalpartial_any;

use const Functional…;

$excerpt = partial_right('substr', 0, 5);

echo $excerpt('Lorem ipsum dolor si amet.');

// Lorem

$fixed_string = partial_left('substr', 'Lorem ipsum dolor si
amet.');

echo $fixed_string(6, 5);

// ipsum

$start_placeholder = partial_any('substr', 'Lorem ipsum dolor si
amet.', …(), 5);

echo $start_placeholder(12);

// dolor

Currying

Currying is often used as a synonym to partial application. Although both concepts allows us to bind some parameters of a function, the core ideas are a bit different.

The idea behind currying is to transform a function that takes multiple arguments into a sequence of functions that take one argument. As this might be a bit hard to grasp, let’s try to curry the substr method. The result is called a curryied function.

Again, a helper to create such functions is available in the Functional PHP library:

<?php

use function Functionalcurry;

function add($a, $b, $c, $d) {

   return $a + $b + $c + $d;

}

$curryedAdd = curry('add');

$add10 = $curryedAdd(10);

$add15 = $add10(5);

$add42 = $add15(27);

$add42(10); // -> 52

Benefits of functional programing

As we just saw, the functional world is moving, adoption by the enterprise world is growing, and even new imperative languages are taking inspiration from functional languages. But why it is so?

Reduce the cognitive burden on developers

You’ve probably often read or heard that a programmer should not be interrupted because even a small interruption can lead to literally tens of minutes being lost. This is partly due to the cognitive burden or, in other words, the amount of information you have to keep in memory in order to understand the problem or function at hand.

By forcing you to clearly state the dependencies of your functions and avoiding using any kind of external data, functional programming helps a lot in writing self-contained code that can be readily understood and thus reduces cognitive burden a lot.

Software with fewer bugs

We just saw that functional programming reduces the cognitive burden and makes your code easier to reason about. This is already a huge win when it comes to bugs because it will allow you to spot issues quickly as you will spend less time understanding how the code works to focus on what it should do.

But all the benefits we’ve just seen have another advantage. They make testing a lot easier too! If you have a pure function and you test it with a given set of values, you have the absolute certitude that it will always return exactly the same thing in production.

Easier refactoring

Refactoring is never easy. However, since the only inputs of a pure function are its parameters and its sole output is the returned value, things are simpler.

If you’re refactored function continues to return the same output for a given input, you can have the guarantee that your software will continue to work. You cannot forget to set a few state somewhere in an object because your function are side-effect free.

Enforcing good practices

This article and the related book are the proof that functional programming is more about the way we do things instead of a particular language. You can use functional techniques in nearly any language that has functions. Your language still needs to have certain properties, but not that much.

I like to talk about having a functional mindset.

If it is so, why do companies move to functional languages? Because those languages enforce the best practice that we will learn in this book. In PHP, you will have to always remember to use functional techniques. In Haskell, you cannot do anything else, the language forces you to write pure functions.

Summary

This small article is by no mean a complete introduction to functional programming, this is what the Functional PHP book is for. I however hope I convinced you it is a set of techniques worth learning.

We only brushed the surface here, all topics are covered more in depth in the various chapters. You will also learn about more advanced topics like the following:

  • Functors, applicatives, and Monads
  • Type systems
  • Pattern matching
  • Functional reactive programming
  • Property-based testing
  • Parallel execution of functional code

There is also a whole chapter about using functional programming in conjunction with various frameworks like Symfony, Drupal, Laraval, and WordPress.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here