The state of functional programming in PHP

Tweet

With the rise of Javascript, and languages like Python and Ruby, functional programming is becoming more mainstream. Even Java seems to be getting closures in the next version, so does this leave PHP lacking behind or is there an unrealised potential hidden within?

Dynamic dispatch

What exactly defines a functional programming language, is perhaps an open question, but one key element is functions as data. As it happens, PHP kind-of-supports this concept; The syntax permits you to use variables as function-names, making the following possible:


function add($a, $b) {
  return $a + $b;
}
$add = "add";
$add(2, 8); // return 10

Unlike languages with first class functions support, the variable $add isn’t a special type — It’s merely a string, which is evaluated in the context. It may just be a wrapped up eval, but superficially it works similar, once the function has been declared.

It is also possible to explicitly call a function reference with call_user_func. This is interesting, because it accepts different types of arguments, which makes it possible to call a method on an object. More on this in a moment.

Binding state

Another prerequisite for functional programming, is the ability to bind a variable to a function. This bound function serves essentially the same purpose as objects do in object oriented programming, but is usually more fine grained and more flexible.

In languages, which are traditionally associated with functional programming, functions are usually bound with variables, through something called a closure. This is a side effect of the scoping rules of those languages.

Since PHP doesn’t have lexical scope, we can’t use closures, but we can use currying to achieve the same goal. In Wikipedia’s words, currying is the technique of transforming a function that takes multiple arguments into a function that takes a single argument. If that sounds abstract, assume the following:


$add2 = curry($add, 2); // returns a new function reference, to add(), bound with 2 as the first argument
$add2(8); // return 10

Before you try that out, hold your horses — it won’t work, because curry isn’t a PHP function. As it turns out though, it’s possible to create it. Sort of.

Implementing curry

Without going into great details, there are two ways, currying can be implemented in PHP.

For a more detailed explanation, have a look at Partial function application in PHP.

Weighing the options

Looking at the syntax, variable-variables have a much more functional “feel” to them, than a command object. The callback pseudotype does allow one to reference an object + method-name, but even though this is supported by PHP’s internal functions, it get’s bulky in user land code. If a command object feels like functional programming with OOP syntax, then call_user_func feels like functional programming with procedural syntax.

When it comes to performance, the run-time evaluated approach has some serious shortcomings. Currying must be done by creating new static code each time and this can’t be reclaimed until the end of the process. Furthermore, the only way to bind state, using this pattern, is to rely on a global container of some sort, generating a new, unique symbol each time. Since it’s impossible to know, when the callback isn’t referred anymore, it follows, that it’s impossible to safely remove the variable from the global container. Thus, any state bound this way, will be impossible to reclaim for PHP’s memory management system, furthering the risk of the script running out of memory.

In conclusion

So, if the offset for this post was to assert the current options for functional programming in PHP, the only practical solution is currying, using command objects. The awkwardness can be somewhat smoothed out, with a library of utility classes. phunctional is an attempt at this and we might also see some of these ideas emerge into more general purpose frameworks.

Another idea, could be a language level addition to PHP. What we need, is a way to make all callbacks callable with the variable-variable syntax. I’m thinking this could be supported with a magic-method. If an object was to be used as a function, and it implemented said magic method, the method would be called. From a design perspective, it would fit fine with the other magic methods, such as __call and friends.

Declaring functions

Another limitation, which could be addressed at the language level, is the matter of declaring functions in the first place. Currently, functions must be declared in the global scope or through the use of the hideous create_function. There have been some stabs at improving this, on the php-internals team, so maybe we should be as lucky as to see this in PHP 6?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Alexey Zakhlestin

    I think: no chances to have it in php6. PHP community is too conservative for that

  • nick@pixelnix.com

    create_function() is pretty evil but you could use it, in a limited sort of way, to accomplish a partial implementation of currying.

    
    function curry($funcName) {
        $inArgs = array_slice(func_get_args(), 1);
        $serInArgs = serialize($inArgs);
        
        $rfunc = new ReflectionFunction($funcName);
        $funcArgs = $rfunc->getParameters();
        
        $curriedArgs = array_slice($funcArgs, count($inArgs));
        foreach ($curriedArgs as $i=>$arg) {
            $curriedArgs[$i] = '$'.$arg->getName();
        }
        $curriedArgs = implode(', ', $curriedArgs);
        
        return create_function(
            $curriedArgs,
            '
            $rfunc = new ReflectionFunction("'.$funcName.'");
            $args = func_get_args();
            $applyArgs = unserialize("'.str_replace('"', '\"', $serInArgs).'");
            settype($applyArgs, "array");
            foreach ($applyArgs as $arg) {
                array_unshift($args, $arg);
            }
            return $rfunc->invokeArgs($args);
            '
        );
    }
    
  • nick@pixelnix.com

    my bad, sorry for those 2 unreadable comments. it was just a toy example, at any rate.

  • http://www.sitepoint.com/ Paul Annesley

    Fixed :) You need to use both pre and code, like this:
    <pre><code class=”html”>
    // code here
    </code></pre>

  • http://www.tagarga.com/blok stereofrog

    Strictly speaking, your example is not currying, it’s partial application. Currying a function doesn’t involve any concrete values, it just “prepares” the function so that it can be partially applied.

    function add($a, $b) { return $a + $b; }
    $add_curr = curry(‘add’);
    $plus_10 = $add_curr(10);
    echo $plus10(5);

  • http://www.dustindiaz.com polvero

    Well, this doesn’t make much sense why Java would introduce closures, and PHP wouldn’t. PHP is already used mostly as a functional language by many. It’s jQuery to JavaScript, or rather, the jQuery of backend languages. Even most frontend engineers know PHP. I would simply say to implement them in PHP6.

  • http://www.tagarga.com/blok stereofrog

    > stereofrog Says: Your comment is awaiting moderation.

    what is this?

  • kyberfabrikken

    nick@pixelnix.com:
    Yes, create_function can be used for implementing currying (Or should I say partial — Thanks for clarifying, Gosha). Instead of serializing the values, you can put them in a unique, global store and then create a function, which retreives that and dispatches on it. That allows you to use other values, than just primitives. It also allows you to use an object callback as the source.
    Whether you serialize or use a global store, there is no way of reclaming the memory for the PHP runtime, which makes it infeasible for practical use.

    stereofrog:
    Sitepoint uses wordpress, which is a bit clunky. Somehow, your comment got moderated. I’ve fixed it now.

  • Pingback: Geek Daily » Blog Archive » The state of functional programming in PHP

  • Pingback: developercast.com » SitePoint PHP Blog: The state of functional programming in PHP

  • Pingback: Max Design - standards based web design, development and training » Some links for light reading (18/12/07)

  • Pingback: The State of Functional Programming in PHP | David Bisset: Web Designer, Coder, Wordpress Guru

  • ron

    The curry example function could be written quite easily with create_function:

    function curry($func, $args) {
    if (!is_array($args) ) {
    $args = array($args);
    }
    return create_function(“”, “$args = func_get_args(); $args = array_merge(array(” . implode(“”,””, $args) . “), $args); return call_user_func_array(“$func”, $args);”);
    }

  • Paul Meagher

    On the topic of functional programming, you might have wanted to spend a bit of time talking about the array_map, array_filter, and array_reduce functions. These are your main tools for doing functional programming in PHP.

    List comprehension is another feature that is often mentioned in the context of functional programming. Haskell blows most other languages out of the water in terms of its implementation of this feature.

    Hope you keep the functional programming tread alive in a few more posts…. would be nice to see PHP influenced more by functional programming languages rather than predominately OO langs like Java.

  • kyberfabrikken

    Paul Meagher:
    No doubt, there’s a lot to be said on this topic.

    ron (and nick@pixelnix.com):
    You can use create_function for currying in two ways; Marshalling variables to a string and embed it, or using a global storage. My intention with this post, was not to dwell too much about implementation. The point is, that it’s impractical to use, for performance reasons.

  • caiomoritz

    Hi,

    This thread shows Christian Seiler’s patch to include closures in PHP 5.3. Thought you guys would like to check that out. It was posted today.

  • Pingback: SitePoint Blogs » Lexical scope to appear in PHP?

  • Pingback: Newscast for 2007.12.20 | PHP Podcasts

  • binjured

    Bah. Why won’t people accept this is just an issue with PHP and there’s no semantic fix for it? Functions aren’t first-class objects like in languages such as Python. After living with Python for a year I have no love for PHP, but that being said I still think there’s no reason to try and make it something it isn’t. If I can’t do $var = fn then why bother? The kludgy workarounds aren’t worth it.

    PHP isn’t a Functional language. Heck, it’s hardly Object-Oriented (at least before the latest 5 release). Why try to make it that way? If you want functional, if you want proper OO, use a better language. Just my 2 cents.

  • Eric Ritz

    I’ve written a bit about functional techniques in PHP.

  • kyberfabrikken

    In case anybody wants to play around with currying in current versions of PHP, I’ve posted a working implementation here. This is superior to the serializing/embedding technique, which some of the commenters to this post, have shown.

  • Pingback: 今日連結 (2008-03-26) [JeffHung.Blog]