Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 635 posts at DZone. You can read more from them at their website. View Full User Profile

Why I am functophobic

08.15.2012
| 4012 views |
  • submit to reddit
There is a diffused opinion in the PHP world that sometimes we are better off by defining functions in the global namespace than by organizing code into classes. Here's my take on the issues that come up when you write even very few 'function foo()' definitions.

Decomposition

Named functions in a single namespace are the essence of the procedural decomposition: do A, then B, then C; to do A, do A1, A2, and A3 in sequence. Pass the state of the program from one procedure to the next with some shared data structure like a global variable.

The result is that we have lots of isolated functions (think of the array_*() native functions) and some data structure which is manipulated by them. However, you cannot assume much on the data structure as there is no encapsulation: in any point of a program, you can't be sure that an array is immutable, that all its values are of the same type, or that it has a fixed number of elements.

There is very little encapsulation in this picture: every function can modify every piece of the puzzle. If you try to avoid global variables and singletons, you find out that in a procedural decomposition is very difficult as these isolated functions need some context to work correctly, that is imported with a global statement.

The most important issue however, is that functions call other functions directly:

function foo($argument)
{
    // do some stuff...
    return bar($argument, 'something else');
}

so it's pretty impossible to test foo and bar separately (unit testing), or to compose foo() with a different bar().

Functional programming

I'm no lambda sensei, but a functional approach would be different from lots of procedures tied to each other with direct calls. You can pursue this approach with anonymous functions and closures, which behave like functions but are treated as first-class citizens and can be stored in variables.

It is possible to inject a function, so there are seams that you can use for testing or substitutions:

$foo = function($argument, $bar) {
    // do some stuff
    return $bar($argument, 'something else');
};

If you look at other dynamic languages, you'll see that even when functions are actually defined with a name (one of the JavaScript cases) they can be passed around as values:

function foo() { ... }
var myFunction = foo;

PHP functions do not support this pattern, unless you represent them as strings. You can call anything in PHP 5.4, but try currying a named function to see why PHP is not a functional language.

Object-oriented

It's a bit misleading that we sophisticated developers put everything into classes; in OO decomposition we put everything onto objects.

So there are no isolated functions that pair with data structures, but only methods implemented on objects in general. Those pair with protocols expressed explicitly in interfaces or implicitly in duck typing.

If you work with OO decomposition, you accept that logic does not make sense by itself, but only attached to an object. In the case of array functions, they are placed on the array itself, which due to PHP's legacy is a primitive value instead of an object.

class Foo
{
    public function __construct(Bar $bar)
    {
        $this->bar = $bar;
    }

    public function __invoke($argument)
    {
        // do some stuff...
        $this->bar->__invoke($argument, 'something else');
    }
}

(just using __invoke here in place since we have no real names in these examples.)

So PHP programmers like me are not functo-phobic, but procedure-phobic: we want to think of objects talking to each other and not of a tree of calls, which we deem (at least in my case) a lower-level abstraction with respect to an object graph.

Functional PHP?

There is still one problem with anonymous functions as implemented in PHP, even if they can substitute the OO approach.
In PHP we have a (very much optional) type system. Objects can work with either duck typing or Java-like interfaces:

interface Collation
{
    /**
     * @return int -1, 0 or 1. -1 if $char precedes $another
     */
    function compare($char, $another);
}

I can now use the Collation type hint:

class Collection
{
    public function sort(Collation $c) { ... }
}

In other cases I may prefer duck typing:

class Collection
{
    public function sort($c) { ... }
}

and I hope that my tests catch if I call a unexistent method on $c objects.

But there's no equivalent to interfaces for anonymous functions, and you're left with duck typing:

$compare = function($char, $another) { ... };
$sort = function($collection, $c) { ... };

There is no way to say that when you pass a Closure as an argument to some method or other function it has to respect a certain protocol.

But how many arguments $c takes? Of which types? Does it have to return something? Where do we express all these things without duplication, separately from the hundreds places where we create $c anonymous functions? And separately from the hundreds places where we accept $c anonymous functions?

That's the role of an interface and why I often use interfaces with a single method in PHP, even when closures would be an option. Closures are very quick to define on the calling side but complex to document on the receiving side.

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)