PHP 5.3 Feature: Late Static Binding
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!
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.
Ted: I must confess I agree but breaking backwards compatibility is very unhelpful so I can understand why it was implemented in this way
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
Jan: I’m delighted to hear that you found this post useful, thank you for taking the time to comment
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 :)
Paul, thanks for the additional tips, that’s really helpful! And yes, the wait for LSB was a long one …
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!
Jared, thanks for emphasizing that !
I found this a really clear and concise education on LSB. Much appreciated.
Thanks Lorna for nice and clear explanation about the concept; in fact I was confused while reading php manual.
Brilliant explanation. I was so confused with the book I’m reading now and it was so simple :) Thanks.
Pingback: Johnny Come Lately: PHP Late Static Binding | Sharon Lee Levy's Blog
Thanks – I was asked this in an interview recently – wish I’d read this before, it would have been a far clearer response
Awesome article, loved the way you explained, Finally I understood the concept of late static binding.
Thanks for sharing.
And keep up the gr88 work..