The State of Functional Programming in PHP 5.3.x

A few weeks ago, I started looking into the possibility of functional programming in PHP. I stumbled across the capability of defining anonymous functions — starting with PHP 5.3.0. These can be used to define closures with bound variables and also for partial application or currying. Higher order functions can also be defined.

All anonymous functions are implemented through the internal Closure class — which is strange since anonymous functions can be used to implement closures, but anonymous functions are not closures. It takes advantage of the __invoke() magic in PHP 5.3.x. This means that alternate implementations or libraries taking further advantage of anonymous functions could be created rather easily.

Anonymous Functions

It is very easy to define an anonymous function:


$variable = function ($arg) {
  return $arg+1;
};

This is very close to what JavaScript programmers typically call a closure, for reasons we’ll see shortly.

Note: In PHP 5.4.x (currently in alpha — development preview), an anonymous function defined inside of a class can use the $this variable to access class properties and methods.

Closures and Bound Variables

A closure is an anonymous function that encloses part of the external scope surrounding it. Here’s an example:


// Assign value to variable to be bound
$variable = 3;
// Create a closure using a variable outside of the scope of the anonymous function.
$closure = function ($arg) use($variable) {
  return $arg + $variable;
};

One must explicitly bind variables in the outside scope by using the keyword use. Binding variables in PHP is, by default, through early binding. This means that the values seen by the anonymous function are the values that were bound at the time the function was defined. One can implement late binding by passing in the variables to be bound by reference in the use parameters. For example:


// Define the greeting
$greeting = "Hello!\n";
// Define a function and bind a variable by reference (late binding)
$f = function() use(&$greeting) {
  echo $greeting;
};
// Run the closure
$f();
// Change the greeting
$greeting = "Hi!\n";
// Run the closure
$f();

This would output:


Hello!
Hi!

JavaScript uses late binding, where the value seen is whatever the bound variable’s value is at the time of the anonymous function’s execution. Variable scope overlaps one level of nesting — closures can access variables in the scope directly containing it. In PHP, I have nonesuch luck. This is why anonymous functions are commonly called closures in JavaScript, it is so common to use its implicit binding that most programmers don’t notice that they might not even be creating a real closure. (Since the variables in the containing scope are always available to the anonymous function (unless there are optimizations in the interpreter or compiler), it might technically still be a closure.)

Partial Application of Functions

If there is a general function that accepts many variables and one wants to create a function that fixes most of the variables, one can partially apply a function. This takes a function with a certain number of parameters and returns a function that accepts fewer parameters. For instance, I can take a saddle function (a 3-d function that looks like a saddle) and turn it into a 2-d parabola (which is actually the curve at y = 5):


$general_function = function($x, $y) {
  return $x*$x - $y*$y;
};
$partial_function = function($x) use($general_function) {
  return $general_function($x, 5);
};

Higher Order Functions

Higher order functions are functions that accept functions as their parameters. A common higher order function is the compose function. It accepts two functions and returns a function. All of the inputted functions must accept the same number of parameters and resulting function will accept the same number of parameters.


function compose(&$f, &$g) {
  // Return the composed function
  return function() use($f,$g) {
    // Get the arguments passed into the new function
    $x = func_get_args();
    // Call the function to be composed with the arguments
    // and pass the result into the first function.
    return $f(call_user_func_array($g, $x));
  };
}

Other common functions are map, filter, & fold (reduce in some cases).

The function map takes an array and a function, applies the function to each element in the array, returning the resulting array:


// Convenience wrapper for mapping
function map(&$data, &$f) {
  return array_map($f, $data);
}

The filter function takes an array and a function (boolean). It applies the function to each element in the array and appends it to the array if the function returns true.


// Convenience wrapper for filtering arrays
function filter(&$data, &$f) {
  return array_filter($data, $f);
}

The fold function aids in taking an array and turning it into a scalar (single) value:


// Convenience wrapper for reducing arrays
function fold(&$data, &$f) {
  return array_reduce($data, $f);
}

// sum over an array using the fold function
$sum = function ($values) {
  return fold($values, function($u, $v) {
    return $u += $v;
  });
};

Functions as Objects

Unfortunately, the class which is implemented internally for anonymous functions does not support instantiation. This has the side effect of not allowing the Closure class to be extended. This is not a huge deal, since the __invoke() magic could be used to create a class that can be used the same way as the internal class. For instance:


class Lambda {
private $anonymous;
  public function __construct($f) {
    $this->anonymous = $f;
  }
  public function __invoke() {
    $x = func_get_args();
    return call_user_func_array($this->anonymous, $x);
  }
}

$a = new Lambda(function($x) {
  return $x*$x;
});

$y = $a(5);
echo "$y\n";

If one implemented the ArrayAccess interface, one could create objects that as extensible as JavaScript objects.

Example Code

There are more examples for one to peruse over at my github account. Here are the links to the gists:

  1. Composing Functions in PHP
  2. Sketch of Making a Functional Style Controller (Please, don’t emulate this! This is terrible, I have a better way of doing it in the works.)
  3. Functional Programming in PHP
Advertisements

6 thoughts on “The State of Functional Programming in PHP 5.3.x

  1. Hey Jillian! I love your blog and amazing background. Lots of beauty and brains there. This is a great article about functional programming in PHP.. I’m experimenting with functional programming to generate pages of HTML. HTML can be thought of as a composition of functions – body(header()+container(left_side()+right_side())+footer() ).

    Here is my comment:
    http://www.php.net/manual/en/functions.anonymous.php#106046

    One of the darksides about functional programming though is performance. Profile an operation with XDEBUG using array_map vs the imperative way. Not that its a deal breaker, but the function calls do have a cost in the end.

    1. Thank you Lenny! I had an idea like that, too. I wanted to extend it into the controller and model parts of an MVC framework. However, decomposing all of the common functionality into simple functions takes a lot of work. I may still work towards that goal though. I’m not sure if I would build it in PHP, though I might do it to showcase the functional aspect of PHP.

      I had not run any functional versus imperative code benchmarks in PHP. Thanks for pointing out the performance hit. I’m wondering if the performance is better in PHP 5.4.

      1. >> I wanted to extend it into the controller and model parts of an MVC framework. However, decomposing all of the common functionality into simple functions takes a lot of work. I may still work towards that goal though. I’m not sure if I would build it in PHP, though I might do it to showcase the functional aspect of PHP.

        I have the same idea from time to time, even got a little bit of code. Let us know if it ever moves anywhere and you need a hand 😉

        Meanwhile, I wrote a similar post http://blog.lcf.name/2011/12/functional-programming-in-php.html (just in case, so to speak… :))

  2. Hi everybody,
    this was pretty nice post about functional programming.
    I would like to comment performance issue mentioned above.
    For sure, functional way might be slower then imperative. Thats really no big surprise considering
    we are discussing PHP here.

    But as functional guru which I recommend to your attention, Mr. Scott Wlaschin from
    http://fsharpforfunandprofit.com/, remarks you should follow this rules:

    1/ Safety
    2/ Quality
    3/ Quantity

    In this order 🙂

    In most cases the speed is not the most critical factor. After all, you can rewrite your bottleneck in imperative way.

Leave a Reply to Tobias Sjösten (@tobiassjosten) Cancel reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s