/usr/portage

Functional programming in PHP 16

PHP has traditionally been a simple, procedural language that took a lot of inspiration from C and Perl. Both syntax wise and making sure function signatures are as convoluted as possible. PHP 5.0 introduced a proper object model but you know all of that already. PHP 5.3 introduced closures and PHP 5.4 improved closures very much (hint: $this is available per default).

What is functional programming anyway?

After a few years introducing more and more functional elements to my source code, it is not that straight forward to answer. I still do not have a coherent definition, but “I know it when I see it”. Let me put it that way: functional programs generally do not alter state, but use pure functions. Pure functions take a value and return another value without altering its input argument. The opposite example is a typical setter in an object oriented context.

Typical functional programming languages support higher order functions, that is, functions that take or return other functions. A lot of them support a concept that is called currying or partial function application (PFA).

Additional characteristics found in functional programming languages are elaborated type systems that e.g. use option types to prevent null pointer issues typical for imperative or object oriented programming languages.

Functional programming has a lot of desirable attributes: not fumbling with state makes parallelism easier (not easy, it’s never easy), focusing on the smallest unit of reusable code, a function, can lead to really interesting effects with regards to reusability, requiring functions to be deterministic is generally a good idea for stable software.

What does PHP has to offer?

PHP is not a “real” or “pure” functional language. Far from it. We don’t have a proper type system, the cool kids make fun of our exotic syntax for closures and we have array_walk() that looks functional but allows altering state.

Nevertheless, there are a few interesting building blocks for functional programming. Let’s start with call_user_func, call_user_func_array and $callable(). call_user_func takes a callback and a list of arguments and invokes the given callback with the given arguments. call_user_func_array does something similar, except, it takes an array of arguments. That’s pretty much the same as fn.call() and fn.apply() in JavaScript (without passing a scope). A less well known shiny new thing in PHP 5.4 is the ability to call functions directly on callables. callable is a meta type in PHP (as in: it consists of various underlying types): a callable can be a string to call simple functions, an array of <string,string> to call static methods, and array of <object,string> to call object methods, an instance of Closure or anything implementing the __invoke() magic method, also known as a Functor. This will look like that:

$print = 'printf';
$print("Hello %s\n", 'World');

Additionally, PHP 5.4 introduces a new type hint “callable” that provides a simple contract for the callable meta type.

PHP also supports anonymous functions. As I said before, the Haskell community made fun us but hey, we finally have it. The jokes are somewhat expected, because the syntax is somewhat verbose. Let’s see a simple Python example.

map(lambda v: v * 2, [1, 2, 3])

Nice. Let’s see a little Ruby example:

[1, 2, 3].map{|x| x * 2}

Also pretty, nevertheless we use a block here and not strictly a lambda expression. Ruby has lambda as well, but List.map happens to take a block, not a function. Next example is Scala:

List(1, 2, 3).map((x: Int) => x * 2)

For a strictly typed language that is pretty compact. Now look at PHP:

array_map(function ($x) {return $x * 2;}, [1, 2, 3]);

A function keyword and no implicit return is what makes it look quite cumbersome. But anyway, it works. Another building block for functional programming.

array_map is a good start, there is also array_reduce. Another two important functions.

A real world functional example

Let’s start with a simple program to calculate totals in a shopping cart:

$cart = [
    [
        'name'     => 'Item 1',
        'quantity' => 10,
        'price'    => 9.99,
    ],
    [
        'name'     => 'Item 2',
        'quantity' => 3,
        'price'    => 5.99,
    ]
];
 
function calculate_totals(array $cart, $vatPercentage)
{
    $totals = [
        'gross' => 0,
        'tax'   => 0,
        'net'   => 0,
    ];
 
    foreach ($cart as $position) {
        $sum = $position['price'] * $position['quantity'];
        $tax = $sum / (100 + $vatPercentage) * $vatPercentage;
        $totals['gross'] += $sum
        $totals['tax'] += $tax
        $totals['net'] += $sum - $tax; 
    }
 
    return $totals;
}
 
calculate_totals($cart, 19);

Yes it is a simple example that will only work for a single market but it’s a halfway complicated calculation and we can easily refactor into a more functional style.

Let’s use higher order functions first:

$cart = [
    [
        'name'     => 'Item 1',
        'quantity' => 10,
        'price'    => 9.99,
    ],
    [
        'name'     => 'Item 2',
        'quantity' => 3,
        'price'    => 5.99,
    ]
];
 
function calculate_totals(array $cart, $vatPercentage)
{
   $cartWithAmounts = array_map(
       function (array $position) use ($vatPercentage) {
           $sum = $position['price'] * $position['quantity'];
           $position['gross'] = $sum;
           $position['tax'] = $sum / (100 + $vatPercentage) * $vatPercentage;
           $position['net'] = $sum - $position['tax'];
           return $position;
       },
       $cart
   );
 
   return array_reduce(
       $cartWithAmounts,
       function ($totals, $position) {
           $totals['gross'] += $position['gross'];
           $totals['net'] += $position['net'];
           $totals['tax'] += $position['tax'];
           return $totals;
       },
       [
           'gross' => 0,
           'tax'   => 0,
           'net'   => 0,
       ]
   );
}
 
calculate_totals($cart, 19);

Now we no longer alter state, not even in the function itself. array_map() returns a new array of cart positions with gross, tax, net amounts and array reduce puts together the totals array. But can we go further? Can we make it much simpler?

What if we destructure the program further and abstract it to what it really does:

* Sum an element of an array multiplied it by another element * Take away a percentage of that sum * Calculate the difference between the percentage and the sum

Now we need a little helper. This little helper is functional-php, a small library of functional primitives I’ve been developing for a few years now. First, there is Functional\pluck() that does the same as _.pluck() from underscore.js. Another helpful function is Functional\zip(). It “zips” together two lists, optionally using a callback. Functional\sum() sums the elements of a list.

use Functional as F;
$cart = [
    [
        'name'     => 'Item 1',
        'quantity' => 10,
        'price'    => 9.99,
    ],
    [
        'name'     => 'Item 2',
        'quantity' => 3,
        'price'    => 5.99,
    ]
];
 
function calculate_totals(array $cart, $vatPercentage)
{
    $gross = F\sum(
        F\zip(
            F\pluck($cart, 'price'),
            F\pluck($cart, 'quantity'),
            function($price, $quantity) {
                return $price * $quantity;
            }
        )
    );
    $tax = $gross / (100 + $vatPercentage) * $vatPercentage;
 
    return [
        'gross' => $gross,
        'tax'   => $tax,
        'net'   => $gross - $tax,
    ];
}
 
calculate_totals($cart, 19);

A good counter argument is: is that really easier to read. At first: no, at a second look: you’ll get used to it. It took me while to get used to the syntax of Scala, it took a while to learn object oriented programming and it takes a while to grasp functional programs. Is this the perfect solution? No. But it shows what you can do by thinking more in terms of applying functions to data structures instead of using expressions like foreach to handle work on data structures.

What else can we do?

Ever had issues with null pointer exceptions? There is php-option that provides an implementation of a polymorphic “maybe type” using a PHP object.

Than there is partial application: it transforms a function that takes n parameters to a function that takes <n parameters. Why is that helpful? Think about extracting the first character from a list of strings.

The boring way:

$list = ['foo', 'bar', 'baz'];
$firstChars = [];
foreach ($list as $str)  {
    $firstChars[] = substr($str, 0, 1);
}

The functional’ish way without PFA (partial function application):

array_map(function ($str) {return substr($str, 0, 1);}, ['foo', 'bar', 'baz']);

The way with PFA using reactphp/curry (my favorite currying implementation for PHP):

use React\Curry;
array_map(Curry\bind('substr', Curry\…(), 0, 1), ['foo', 'bar', 'baz']);

Yes. (HORIZONTAL ELLIPSIS, U+2026) is a valid function name in PHP. But if you do not like that, use Curry\placeholder() instead.

The end

Functional programming is a fascinating topic and I needed to name a single thing that I learned the most from in the
last years, it was looking into functional paradigms. It’s so different it will make you brain hurt. But in a good way.
Ah, one last thing: read Real World Functional Programming. It’s full of good advice and real world examples.

Update

Thank you Christopher Jones for fixing the higher order function example (the second step).

Update II

Thank you Anthony Ferrara for pointing out that the array_map example was wrong. Gotta love parameter ordering.

Update III

There is a russian translation.

Update IV

Thanks for the serbo-croation translation

Filed on 17-01-2013, 02:02 under , , , , , , , & 16 comments & no trackbacks

Trackbacks

Trackback specific URI for this entry

No Trackbacks

Comments

No comments

Add a Comment & let me know what you think