Blog Post RSS ?

Blogs » PHP » The state of functional programming in PHP
 

The state of functional programming in PHP


  • Save to
    Del.icio.us

by Troels Knak-Nielsen

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?

This post has 22 responses so far

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

     
  2. 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);
            '
        );
    }
    
     
  3. my bad, sorry for those 2 unreadable comments. it was just a toy example, at any rate.

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

     
  5. 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);

     
  6. 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.

     
  7. > stereofrog Says: Your comment is awaiting moderation.

    what is this?

     
  8. 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.

     
  9. […] has published a great article exploring functional programming in PHP. With the rise of Javascript, and languages like Python and Ruby, functional programming is […]

     
  10. […] the SitePoint PHP Blog today, Troels Knak-Nielsen has written up a post concerning the current state of functional programming in PHP. With the rise of Javascript, and […]

     
  11. […] The state of functional programming in PHP […]

     
  12. […] Knak-Nielsen writes a good overview on how PHP relates to functional programming and might be where PHP is heading in the next version. PHP is dynamically-typed and weakly-typed. […]

     
  13. 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);”);
    }

     
  14. 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.

     
  15. 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.

     
  16. 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.

     
  17. […] mentioned briefly, in my last post, that Wez Furlong made a patch back in March, that allows a native syntax for creating anonymous […]

     
  18. […] Closures […]

     
  19. 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.

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

     
  21. 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.

     
  22. […] The state of functional programming in PHP […]

     

Sponsored Links

Leave a response

You are not logged in, log in with your SitePoint Forum username and password.

-OR- Post Anonymously

* Make sure any code samples are escaped (i.e. ‘<b>’ becomes ‘&lt;b&gt;’).

If not logged in, your comments will be placed in a moderation queue. This means your comment may not appear until one of our moderators approves it.

SitePoint Marketplace

Buy and sell Websites, templates, domain names, hosting, graphics and more.

Logo Design, Web page Design and more!

99designs

  • Custom logo designs created ‘just for you’.
  • Pick the design you like best.
  • Only pay if you’re satisfied with the result.

Want More Traffic?

Get up to five quotes from qualified SEO specialists, with no obligation!

Get A Free SEO Quote Now!