Dec 09

On Closures in PHP

Posted by

Published in , , ,

PHP is known to be a very ugly language. In fact, PHP makes it almost effortless to write really ugly code. There are certain methodologies and patterns that try to alleviate this problem but even then, it’s still a piece of cake writing horrid code.

If we look at almost any other high level language, there are clean and elegant ways of initialising arrays, assoc. arrays and/or objects. In PHP, there is no support to initialise objects in a clean way. Consider this in JavaScript:

var my_obj = {first_name: 'James', last_name: 'Dunne'}

That will initialise an object, with ‘first_name’ and ‘last_name’ as properties of my_obj. The equivalent in PHP is this:

$my_obj = (object) array('first_name' => 'James', 'last_name' => 'Dunne');

We have to go around all the houses, declare an associative array and then cast it as an object, completely disregarding the ugly way that the array is initialised. I don’t have tell you which one looks cleaner, especially when you have a function that takes a stdClass object as a parameter and you’re using it all over the place. I’d hate to think what phpQuery would look like. Scratch that, PHP isn’t JavaScript (and definitely not as cool). There are always going to be certain awkward points about a language, but PHP has  many of these.

Then there are the massive inconsistencies in style that we have to remember. Was that str_to_lower or strtolower? Is it strreplace or str_replace? Okay, every PHP developer knows these ones by now but it’s besides the point.

PHP has been accumulating extensions over the many years, so this sort of thing is expected. It can’t easily be cleaned up either but it does make PHP look like what it is: a language that has been cobbled together. If you look closely enough, you can notice the transition from plain structured, to procedural to OO, with each phase leaving parts of its old self behind.

But then they added something that’s meant to be really cool…

Closures

And like usual, they butchered the concept. PHP 5.3 has closures and, due to the daft scoping rules, we also have to declare the variables we want to use. Personally, this is a bit stupid and just clutters up the number of keywords in use. However, I believe closures, on the whole, are a great addition. Just like polymorphism,  they can massively help reduce the need for switch statements, but are definitely not limited to just this use-case. In fact, this article should serve to demonstrate the large range of possibilities.

For example:

function my_func($some_var, $my_var)
{
    switch ($some_var)
    {
        case 1:
            some_func($my_var());
        break;

        case 2:
            some_other_func($my_var);
        break;

        case 3:
            omg();
            many($my_var);
            funcs();
        break;
    }
}

This sort of thing is GREAT for simple usage, but it’s very rigid and is a serious pain when you want to do something a very similar many times over. Now, with closures (disregard the danger in this example):

function my_func($some_var, $my_var)
{
    $callbacks = array(
                        function () use ($my_var) { some_func($my_var); },
                        function () use ($my_var) { some_other_func($my_var); },
                        function () use ($my_var)
                        {
                            omg();
                            many($my_var);
                            funcs();
                        }
                      );

    $callbacks[$some_var]();
}

In real, production use, we’d have bounds checking but what’s one more function definition for the obvious power this gives us? Now we have an alternative to a static, rigid control structure that:

  • Can be passed around as any other data structure.
  • Can be changed on the fly.
  • And based on the above statements, can reduce duplication a hell of a lot.

And, in true sales man style: many more!

In object context

Closures are a bit iffy in object context, which stops us using $this-> inside a closure’s body.  However, there is a work around. You would have to assign $this to a local variable and then use that local variable in the closure. For example:

class My_class
{
    private $my_var;

    public function __construct($my_var)
    {
        $this->my_var = $my_var;
    }

    public function get_var()
    {
        return $this->my_var;
    }

    public function my_func()
    {
        $self = $this;

        return function () use ($self)
        {
            return $self->get_var();
        };
    }
}

Even with this solution, you either have to expose certain member variable (breaking your encapsulation), make a getter (like I’ve done above) or you could use magic methods. Again, not really an ideal solution. The good news is that this has been fixed in the next release of PHP.

Cleaning up

For most of this week, I’ve been cleaning up the code on Cosmetic Dentistry Guide and I used closures to handle the bitmasks passed to interface functions. In the beginning, I was simply experimenting with them before I had the chance to really stretch and pull what I could do with the new handler. It turns out they have helped me massively and I’ll definitely be  on the look out for new opportunities to use them in my PHP code and you should too.