PHP 5.3 Feature: Late Static Binding

With the release of PHP 5.3 comes the functionality "late static binding", a feature which I've been impatient to see for quite some time! This is something a lot of developers have been puzzled by in earlier versions of PHP 5, probably without being aware it had a name. In PHP 5.3 there is functionality for dealing with this situation so here's an outline the problem and then a look at how to avoid it with PHP 5.3.

The issue arises because of the way PHP classes refer to themselves. Keywords like self are resolved at compile time, which means that where classes inherit from one another, self will always relate to the class where it is mentioned and not the class which is inheriting it. Many class hierarchies will have common functionality across classes but which need some form of "which class is this?" awareness, either to access the class name or a variable declared in the class so that a method declared in the parent can be used in all inheriting classes. Without late static binding, this will always resolve to the declaring class, leaving developers the choice between copy/pasting the same function into every class that needs it or turning their static method into a dynamic one, since $this resolves as expected.

It's perhaps clearer to illustrate the problem by showing an example. Here I have a base class Record, which all my other classes will extend from (in the tradition of these things, its an over-simplified and not-terribly-useful example but I think it shows the point):

class Record {
 
    protected static $tableName = 'base';
 
    public static function getTableName() {
        return self::$tableName;
    }
}

So, I'm ready to write my first useful class, which will be my user class - it will have its own variables but can inherit the function since they're identical.

class User extends Record {
    protected static $tableName = 'users';
}

So if we call the getTableName method against the User class - what would you expect the output to be?

User::getTableName();  // returns "base"

That isn't what I expected when I first ran into this scenario. This is a pretty common thing to want to do, I've seen people have this problem when implementing active record patterns, when creating re-usable form widgets with their own templates, and in countless other applications. With PHP 5.3, the static keyword has been implemented to allow us to get the value of the class the code is actually executing inside rather than where it was inherited from. We simply replace the "self" in our Record class with "static":

class Record {
 
    protected static $tableName = 'base';
 
    public static function getTableName() {
        return static::$tableName;
    }
}

This keyword evaluates differently and has awareness of its calling context - so if we repeat our call to the getTableName method against the User class:

User::getTableName(); // returns "users"

That's better :)

This feature doesn't make this problem go away - the self keyword still resolves to parent so as PHP developers we will still see this slightly unexpected behaviour where the parent values are returned. However there is now a solution to it in the shape of the new static keyword. Its a feature I'm delighted to see included and I'm sure it'll be helpful in a wide range of applications!

Does this help you? Have you run into this behaviour before? And how did you solve it? Leave a comment!

14 thoughts on “PHP 5.3 Feature: Late Static Binding

  1. I would have preferred they reassign self:: to refer to the current class, and then allow parent:: to refer to the parent class. It gives better context about what you're referring to. The keyword static:: doesn't give any context at all. I find that awkward.

  2. Thank you very much for your explanation of the Late Static Binding in a human language. I am quite a beginner with OO PHP and this helped me understand this new feature.

    Also, I must agree with Ted on one hand that the 'self' keyword gives better context as to what you are referring, though it would create potential problems to change it. Anyway, thanks for your brief tutorial

  3. You can also now use get_called_class() which saves you even needing the static member variable.

    http://php.net/manual/en/function.get-called-class.php

    Example:

    class Boo {
    public static function reaction() { return get_called_class(); }
    }

    class Yay extends Boo {}

    var_dump( Boo::reaction() );
    var_dump( Yay::reaction() );

    Like you, I've been waiting a looooooong time for late static binding :)

  4. I would like to add that you must re-declare the protected variables in the child class if you are going to have multiple classes inheriting Record. Otherwise PHP will use the same copy of $tableName in memory even with the static keyword.

    Thanks for the article!

  5. Thanks Lorna for nice and clear explanation about the concept; in fact I was confused while reading php manual.

  6. Pingback: Johnny Come Lately: PHP Late Static Binding | Sharon Lee Levy's Blog

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>