Alexander Steshenko | Technical Blog

Functional Programming in PHP

Many have at least heard about Functional Programming, but use PHP for work. While I encourage everyone to try something like Haskell I’m going to try and do some Functional Programming in PHP

What is Functional Programming

An excerpt from wiki:

functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state

If I were to define it in my own words I would do it by comparing the imperative approach to programming with the functional one. In the first case you reason about solving a problem step by step, like this:

Imperative “getting into the house” solution:

  1. get the keys out of the pocket
  2. pick the right key
  3. open the door with the key
  4. enter the house

Functional “getting into the house” solution:

  1. enter the house
    • through the door opened
    • with the right key
    • chosen from all the keys you get out of the pocket

The PHP code

Read the comments:

// Source "data" for the application

// Here is the pocket in which amongst other things we have our keys.
$pocket = array('keys' => array(
                  'carkey'   => 'The Car Key',
                  'housekey' => 'Home Sweet Home',
                  'workkey'  => 'Office'));

// This is the house we need to enter, as you see it's empty without us.
$house = 'empty';

// The door is closed now and to have it opened you must use the right key
$door = 'closed';

/* Imperative entering the house solution */

// Here is where I start. I start with getting the keys out of the pocket
get_keys();
// Next, the program must choose the right key
pick_the_right_key();
// Step 3: we open the door
open_door();
// Finally, enter the house
enter_house();

// checking if it worked:
echo $house; // should echo "full"

// implementation

function get_keys() {
    global $pocket, $keys;
    $keys = $pocket['keys'];
}

function pick_the_right_key() {
    global $keys, $theRightKey;
    $theRightKey = $keys['housekey'];
}

function open_door() {
    global $door, $theRightKey;
    if ($theRightKey == 'Home Sweet Home') {
        $door = 'open';
    }
}

function enter_house() {
    global $house, $door;
    if ($door == 'open') {
        $house = 'full';
    }
}

There is some “state” in which our house, door and the pocket are. We change this state in order to achieve our goal. Step by step.

Some people might say it is bad to use globals. It is, that’s just to illustrate the approach. Most of “object-oriented” PHP projects still utilize the state heavily: singletons, statics, “registry pattern”. Globals even.

Some people might object that they actually never use any of those and only do Dependency Injection and use new frameworks like Symfony 2. Well, you already using functional programming to some degree! Dependency Injection (or parametrization) is a step in that direction. I personally think that “Object Oriented Programming” when done correctly is closer to functional style than imperative or procedural.

While there are a few languages that are “paradigm specific”, functional techniques are slowly getting soaked into many of them, including PHP.

Problem solving with Functional Programming

// Source "data" for the application

// Here is the pocket in which amongst other things we have our keys.
$pocket = array('keys' => array(
                  'carkey'   => 'The Car Key',
                  'housekey' => 'Home Sweet Home',
                  'workkey'  => 'Office'));

// This is the house we need to enter, as you see it's empty without us.
$house = 'empty';

// The door is closed now and to have it opened you must use the right key
$door = 'closed';

/* Functional entering the house solution */

echo // echoing the house state after we entered it, will echo "full"
    enter_house( // We start by defining what we want our program to do i.e. enter the house
        // we specify what we have:
        $house, // the house that we need to enter
        $door, // the door through which the house may be entered
        $pocket // our pocket full of different little things
    );

// See, no "steps" here, just one function call. Here goes the Implementation:

function enter_house($house, $door, $pocket) {
    return // In order to enter the house, we need:
        // try to open the door with the a key found in the pocket
        open_door($door, find_key($pocket))
            // and if it worked
            == 'open'
                // enter the house:
                ? 'full'
                // otherwise - leave it as it was
                : $house;
}

// we defined what enter_house is, now we go deeper defining new functions we introduced

function open_door($door, $key) {
    return // in order to open the door
        // we need the key to be right
        $key == 'Home Sweet Home'
            ? 'open'
            // if it isn't - we leave the door as it was
            : $door;
}

// now let's take a look at finding a key

function find_key($pocket) {
    return
        // amongst all keys in the pocket, we need to choose the right one
        pick_the_right_key($pocket['keys']);
}

function pick_the_right_key($keys) {
    return
        // the housekey is the right one
        $keys['housekey'];
}

We start with “entering the house”. That is, without knowing what we’ll have to do to actually enter it. That highlights the ease of prototyping. In imperative programming you have to think trough all the steps and make sure they will get you where you need to be. In functional programming: you know where you need to be and you try to express what needs to be done for that.

“Functional” is the way you reason about solving a problem. In order to use functional programming you don’t necessary need special tools - you just need to think right. However if a language lacks particular features it may be not worth it to use it for Functional Programming. Let’s review some of the characteristics and features that “make a language a functional one” and what we can do with PHP.

Pure functions, immutable data

Pure functions are those that have no side-effects and for any given set of parameters always return the same result. In languages like Haskell all functions are pure whether you want it or not, in PHP it’s not the case.

What I suggest for PHP developers is to make functions pure when possible. Try to isolate impure stuff (where bugs tend to happen). For that, you need to follow these two leads:

  1. avoid state
  2. avoid mutable data

By “application or system state”, we mostly refer to Input/Output operations, working with data storages and external services. Try to separate application logic from everything state-related whenever possible.

There is not much you can do to avoid mutability in PHP. Simply make sure your pure functions are pure when treated as a “black box”.
Here is an excercise: when you create a function, type “return” the next line. This way you:

  1. don’t have much place to create mutable data
  2. are forced to introduce new functions to keep the code sane

For instance, you could have that enter_house function coded like this:

function enter_house($house, $door, $pocket) {
    $key = find_key($pocket);
    $door = open_door($door, $key);
    if ($door == 'open') {
        $house = 'full';
    }
    return $house;
}

While the function still does the same, you create temporary variables when can be avoided and may omit introducing functions thus spoiling decomposition. If you need temporary variables, consider “values binding”:

/*
 * Imagine, we need to open two doors with the same key in order to enter the house
 */
function enter_house($house, $door1, $door2, $pocket) {
    return
        // When BOTH (&&) doors are opened with the $key found
        open_door($door1, $key = find_key($pocket)) == 'open' && open_door($door2, $key)
            // we enter the house
            ? 'full'
            : $house;
}

Some mutable data here, but looks and feels like immutable. This is nothing more than a fun trick to start thinking in the right direction. When needed, all the PHP power should be made use of.

First-class functions and Higher Order functions

Wikipedia says that PHP does have First-class functions since the 5.3 version with the exception of partial application and nested functions. They refer to the Closures added. However due to dynamic nature of PHP you could use other types as if they were functions, even before PHP5.3:

/* callable string */

function hello($name) {
    return 'Hello ' . $name;
}

$func = 'hello';
echo is_callable($func) ? 'Yes' : 'No'; // echoes "Yes"
echo $func('John'); // echoes 'Hello John'

/* callable array */

class Helloer {
    public function hello($name) {
        return 'Hello ' . $name;
    }
}

$func = array(new Helloer, 'hello');
echo is_callable($func) ? 'Yes' : 'No'; // echoes 'Yes'
echo call_user_func($func, 'Alex'); // echoes 'Hello Alex'
// Note: with PHP5.4 you can already do this: $func('Alex') even for array-callables

/* callable anonymous function */

$func = function($name) { return 'Hello ' . $name; };
echo is_callable($func) ? 'Yes' : 'No'; // echoes 'Yes';
echo $func('Peter'); // echoes 'Hello Peter'

There is this pseudo-type: “callable” and as of PHP5.4 you are able type hint on it. (https://wiki.php.net/rfc/callable). In prior versions you need to know that callable may be a string, an array or a closure. You can pass/return strings, arrays and closures to/from functions, which gives us the higher order functions:

/*
 * You realize that there may be many ways to open a door and you are not sure
 * which one you'll need when. So you add another parameter to the enter_house function
 * which means "How do we open the door".
 *
 * We can even specify the default value, which PHP allows us, to provide backwards compatibility
 */
function enter_house($house, $door, $pocket, $doorOpener = 'open_door') {
    return
        $doorOpener($door, find_key($pocket))
            == 'open'
                ? 'full'
                : $house;
}

// ... but in case we forgot our keys at work and we really need to get in, we can provide an alternative way
// of opening the door:
function break_in() {
    // for instance, we can open the door with our leg,
    // in this case we don't need a key :)
    return 'open';
}

echo
    enter_house(
        $house,
        $door,
        $pocket,
        'break_in' // this is it, we specify how we want to open the door
    );

Closures and anonymous functions

Anonymous functions are those without a name. We have them as Closures since PHP5.3 (and before that we could create anonymous functions via create_function). Usually useful for some things small when it’s really not worth it to create a real function:

/*
 * Remember the break_in example? The break_in function was so small and simple it hardly needed a name
 * Here is how we could do the same using an anonymous function:
 */
echo
    enter_house(
        $house,
        $door,
        $pocket,
//        'break_in'
        function() { return 'open'; }
    );

Closures are a much more powerful toy through which you can simulate some of the functional programming languages features - I’ll show more on that later. For now, let’s say that we have closures in PHP and in order to create a reference to an outer scope variable you have to use the “use” keyword:

// Modifying the break_in example to use a Closure

$axe = 'Metal Axe';
$breakInWithAnAxe = function($door) use ($axe) {
    /* ... smashing the door with an $axe from the outer scope here ...*/
};

echo
    enter_house(
        $house,
        $door,
        $pocket,
        $breakInWithAnAxe
    );

Recursion

Recursion in computer science is a method where solution to a problem depends on solutions to smaller instances of the same problem.

This is all for the sake of avoiding state and mutable data. Here is an example of pick_the_right_key function implementation for the case when we don’t know if it’s indexed by “housekey”. For instance it could be a situation when we don’t know the key’s color but we remember it has a tiny label on it and we need to check all keys in order to find it.

/*
 * Implementation with a loop.
 */
function pick_the_right_key($keys) {
    // we are thinking imperative again, using "Steps".
    // Even though the steps are all the same:
    while($key = array_shift($keys)) { // take one key
        if ($key == 'Home Sweet Home') { // check if that's the one
            return $key;                // the key is found
        }
    }
}
/*
 * Implementation with a recursion
 */
function pick_the_right_key($keys) {
    return
        // checking the first key in the set
        ($key = array_shift($keys)) == 'Home Sweet Home'
             // return if that's what we need
             ? $key
             // otherwise we pick the right key in what is left of the keys!
             : pick_the_right_key($keys); // Note: array_shift `removes` the first element of the array,
                                          // so at this point $keys is a new value
                                          // that does not contain the $key we already checked
}

In case with the recursion code we don’t have consecutive instructions: we express our needs through calls of other functions. Even if it’s the same function.

Partial Application and Currying

Partial Application and Currying are actually different things. I’m going to speak about partial application: a way to get a new function by partially applying another one.

Let’s say there is a function like this:

// The function that calculates the sum of these four
function add($a, $b, $c, $d) {
    return $a + $b + $c + $d;
}

at some point you realize that you need another one in a few places. One that does the same but the value of $a is fixed so you create something like this:

// the new function could look like this:
$myAdd = function ($b, $c, $d) {
    return add(10, $b, $c, $d);
};

// or this:
function my_new_add($c, $d) {
    return add(1, 2, $c, $d);
}

Normally, in PHP you could just create another function embracing a call to the original function. But if you get on well with the functional way of thinking you may need to dynamically create functions based on existing ones for your particular local needs.

I have a special curry function that makes it possible to create these functions on the fly. Here is the function and how you can use it:

// with partial application, you can do this instead:
$myAdd = curry('add', 10);
$myNewAdd = curry('add', 1, 2);
// or even this
$superAdd = curry($myNewAdd, 2); // so this $superAdd here has $a, $b, $c "partially applied"

echo $superAdd(2);

function curry() {
    $params = func_get_args();
    $function = array_shift($params);
    return function() use ($function, $params) {
        return call_user_func_array($function,
                                    array_merge($params, func_get_args()));
    };
}

Free-point style and functions composition

This is similar to currying from some point of view as it allows you to get a function for a particular local need that composes a few other functions without having to explicitly define it.

Here is what you would normally do in PHP:

function sum($a, $b, $c) {
    return $a + $b + $c;
}

function make_two($a) {
    return $a * 2;
}

function add_three($a) {
    return $a + 3;
}

// you need to create new function like this
function double_sum($a, $b, $c) {
    return make_two(sum($a, $b, $c));
}

// or like this
function my_add($a, $b, $c) { // we are listing the arguments here
    return add_three(
        make_two(
            add_three(
                sum($a, $b, $c) // and here again
            )
        )
    );
}

Here is a function that does this on the fly and a usage example:

$doubleSum = compose('make_two', 'sum');
$myAdd = compose('add_three', 'make_two', 'add_three', 'sum'); // no mention of arguments in this case

function compose() {
    $functions = array_reverse(func_get_args());
    return function() use($functions) {
        $params = func_get_args();
        return array_reduce($functions,
            function($result, $next) use ($params) {
                        return $result === null
                            ? call_user_func_array($next, $params)
                            : $next($result);
                    }
        );
    };
}

The idea here is that with closures many features of programming languages can be simulated.


Comments and feedback are much appreciated. See contact details here