DrupalCon review: Functional programming

Cocomore
If you hear the term of functional programming, you involuntarily think back to lectures, where academical, mostly mathematical problems have been elaborated. Not wrong: Functional programming languages are ideally suited to implement algorithms that contain (complex) mathematical functions. Nowadays they have moved from the universities to serious alternatives of the established programming languages. This is impressively proven by the market giant Facebook, that uses the functional language Erlang for making his chat, and Google with the MapReduce Framework, which is designed to process immensely large amounts of data (in the Petabyte range).
Arrived in Munich

Reading through the curriculum of the Drupalcon I was surprised to find a session of Larry Garfield to the topic functional PHP. Functional programming has as much to do with PHP and Drupal as Cocomore with boredom, so at least my view. How should a functional approach, with all its radiating abstraction and elegance, be integrated in a system that is built up procedural thoroughly? The two worlds seemed different to me: on the one hand Drupal, a classical modular and database-based framework, on the other hand the functional programming with the guiding principle of statelessness. With interest I expected the presentation.

The basics

According to preliminary information about his person, Larry opened his session with a comparison of the current paradigms of programming. The main difference: Imperative programming defines and changes conditions in a sequential order. Each step will be entered by the developer, as he would write a cake recipe. The developer decides, how something will be implemented. In contrast, functional programming (FP) orients on the finish: the developer decides what should be implemented. The process is non sequential and single steps are ideally independent and parallelizable.

Unfortunately Larry covered the scientific basis as the Lambda calculus or the Turing completeness only on the edge; Yet he honorably mentioned the most important theorists (mostly mathematicians) in this area what pleased me.
FP has 4 important features:
  • pure functions, i.e. stateless, deterministic, side effect free functions
  • higher-order functions and first-class functions, i.e. nesting of functions
  • invariant variables (!), functions that return a literal
  • recursion

He especially pointed to the lack of state: Due to the fact that functions in all circumstances always provide same result, source code can not only be better tested, but even verified.

Functional programming in PHP

Larry formulated the transition to PHP as follows:

<troll>PHP is as functional as LISP</troll>

PHP as functional as LISP! Unease spread. Anyone who had programmed in LISP or Haskell and knew PHP 5.2 at the same time, knew about the audacity of this statement. How could you substantiate this claim? First, minimum PHP 5.3 is required. This version provides an important building block for the FP, the so-called anonymous function, i.e. functions without own function names which should be known from other languages, such as JavaScript.
Anonymous function
<?php
$find_pair = function ($card1, $card2) {
  return ($card1->value == $card2->value);
};

$is_pair = $find_pair(new Card('2H'), new Card('8D'));
 
Closures, which differ only by an additional parameter in the section of anonymous functions are a similar construct. This additional data could be fed from outside, for example, an object could be integrated into the function. The disadvantage is that it undermines the benefits of pure FP.
Closure
<?php
$wild = new Card('5H');
$find_pair = function ($card1, $card2) use ($wild) {
  return ($card1->value == $card2->value
          || $wild->value == $card1->value && $wild->suit == $card1->suit
          || $wild->value == $card2->value && $wild->suit == $card2->suit);
};

$is_pair = $find_pair(new Card('2H'), new Card('8D'));
 
You get special benefits if you use anonymous functions and closures in conjunction with functions that expect a function as an argument, for instance array_map or preg_replace_callback.
 
<?php
function something_important(array $arr, $factor) {
  $arr = array_map(function ($a) use ($factor) {
    return $a * $factor;
  }, $arr);
  // ...
}
 
Named after Haskell Curry, we refer to currying as splitting a function with multiple parameters in several functions with a parameter. An addition function for example...
Currying
<?php
$add = function ($a, $b) {
  return $a + $b;
};
 

... could also be nested transferred into two functions.

 
<?php
$add = function ($a) {
  return function($b) use ($a) {
    return $a + $b;
  };
};

$add1 = $add(1);
$add5 = $add(5);

$x = $add5($y);
 
The outcome of this is a new technique of reusability: the partial evaluation. The inner function will use both $add1 and $add5.

 

The last technique with the artificial name memoization serves performance optimization. Already calculated results are cached (here in a static variable), so that when renewed with identical parameters the function does not need to be evaluated again.
 Memoization
<?php
function memoize($function) {
  return function() use ($function) {
    static $results = array();
    $args = func_get_args();
    $key = serialize($args);
    if (empty($results[$key])) {
      $results[$key] = call_user_func_array($function, $args);
    }
    return $results[$key];
  };
}

$factorial = memoize($factorial);

print "Result: " . $factorial(3) . PHP_EOL;
print "Result: " . $factorial(4) . PHP_EOL;
Reality check
The last time I used an anonymous function was in the old days of Drupal 6, to include a sort function. It did not take long until an disgruntled crowd of front-end programmers came to me. Had they recognized the elegance of the anonymous function? Hardly, because on their own server ran a PHP 5.2 version. The only thing they got to see was a plain white screen.

Inspired by the lecture, I was trying to implement the gained knowledge in a project which used a parameterized integral function (fα,β(x), α, β, x n-dimensional each) to calculate an index.


<?php
function myfunction($alpha, $beta, $x) {

}

 

Since the parameters remained arbitrary but fixed at run time, a partial evaluation was an opportunity, so that the function in the end depended on x.

<?php
function index($x) {
  $myfunction = function ($alpha, $beta) use ($z) {
  //...  
  };
  
  $result1 = $myfunction($x[1]);
  $result2 = $myfunction($x[2]);
  //...
}
Conclusion
Functional programming can be used in PHP. It depends on the task if FP should or can be used. If you use FP, it should be clear that a stateless, side-effect-free programming is difficult to achieve; Think of closures: Strictly speaking, a piece of information, so a state is induced here from the outside, what is contrary to the principle of the statelessness. The use of anonymous functions will likely achieve popularity, for reasons of clarity and structure. A more complex application of FP is conceivable in tree-like data structures.
The large success of FP on Drupal will probably hold off. Selectively, there is a field of application. As an example, Larry has called the following passage from the Drupal 8 core.
 

<?php
public function onKernelControllerLegacy(FilterControllerEvent $event) {
  $request = $event->getRequest();
  $router_item = $request->attributes->get('drupal_menu_item');
  $controller = $event->getController();

  // This BC logic applies only to functions. Otherwise, skip it.
  if (is_string($controller) && function_exists($controller)) {
    $new_controller = function() use ($router_item) {
      return call_user_func_array(
        $router_item['page_callback'],
        $router_item['page_arguments']);
    };
    $event->setController($new_controller);
  }
}

 

Let's wait and see whether the new features of PHP 5.4 regarding anonymous functions are going to be accepted by the community. Especially object-oriented frameworks should benefit from the new features (e.g. the Object extensions).

 

Our expert

Cocomore

Any questions or input? Reach out to our experts!

Send e-mail

As an agency for marketing, IT and experience design, Cocomore develops communication, e-commerce and CRM solutions (Customer Relationship Management) with a total of 180 employees at its locations in Frankfurt am Main, Cologne, Geneva (Switzerland) and Seville (Spain). Cocomore's customers include Merck, Nestlé, Procter & Gamble, Rabobank, Syngenta, Tele Columbus and the European Broadcasting Union. Cocomore has realized projects in more than 30 countries.