What is new in PHP 5.3 – part 2: late static binding
November 15, 2007
In the first part of this series I wrote about namespaces, in the second part we will deal with late static binding, which is a very exciting new feature in PHP 5.3 and which promise some really nifty code.
This topic attracted attention after Zend’s webcast about the Zend Framework. There was a little outcry in the PHP blogosphere, that the ActiveRecord examples presented in this webcast can’t work in PHP even with the version 5.2. Now with late static binding it is possible to implement this style of ActiveRecord almost correctly.
Late static binding basic
First let me introduce what late static binding is about. I am not going to write too much about the basics, because fortunately I get a helping hand
. So the base problem is the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php class A { public static function who() { echo __CLASS__; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); // Output: &qout;A&qout; ?> |
Static references to the current class like self:: or __CLASS__ are resolved using the class in which the function belongs, as in where it was defined, so when we call the test() method on class B it will call the who() method of class A.
PHP 5.3 introduces a new possibility by allowing a keyword that references the class that was initially called at runtime:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // Here comes Late Static Bindings } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); // Output: "B" ?> |
This is the basic behavior of the static keyword in this context, you can get more information in the manual. Now back to the ActiveRecord.
Facing the problem
Zend’s proposal was something similar:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php class ActiveRecord { public static function findByPk($id) { // something maqic } } class Blog extends ActiveRecord {} Blog::findByPk(1); ?> |
The conception is nice, the base implementation of findByPk() finds out from the name of the child class the name of the table on which it should be operate. There is only one (huge) problem with this code, when findByPk() is called it can’t determines the name of the class on which it was called. There was an ugly workaround using debug_backtrace(), but its performance was quite poor, so finally it was not used in ZF.
After the late static binding introduction you may come up with the following code in PHP 5.3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class ActiveRecord { public static function getClass() { return __CLASS__; } public static function findByPk($id) { $calledClass = static::getClass(); // The magic... } } class Blog extends ActiveRecord { public static function getClass() { return __CLASS__; } } Blog::findByPk(1); ?> |
Running this code the value of $calledClass will be “Blog”. This is great, but it would be very annoying if we have to add the getClass() method to every child class. Fortunately with the late static binding we get a great new function too: get_called_class(), which returns the name of the current calling scope. Using this function we get a nifty code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php class ActiveRecord { public static function findByPk($id) { $calledClass = get_called_class(); // The magic remains... } } class Blog extends ActiveRecord {} Blog::findByPk(1); ?> |
This works very well, but unfortunately we can’t be absolutely happy, because there is a big flaw (I believe it is) in the current implementation of late static binding. Michael Lively pointed to this problem on the internal list and on his blog. How does this problem affect our example? Imagine that we want a simple logging functionality only in the Blog class. Consider the following code (it seems to a logical and suitable solution for this task):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php class ActiveRecord { public static function findByPk($id) { $calledClass = get_called_class(); // The magic remains... } } class Blog extends ActiveRecord { public static function findByPk($id) { // We want to log something. // Then the parent should do the magic. parent::findByPk($id); } } Blog::findByPk(1); ?> |
If you try to run this program maybe you will surprise, because the value of the $calledClass variable will be “ActiveRecord”. OOPS! What here happens: parent will resolve to ActiveRecord and this breaks late static binding. From the manual: “Late static bindings’ reslution will stop at a fully resolved static call with no fallback”. It is possible that this explanation is not completely exact (maybe somebody from the internal list can explain it more precisely), but the substance is that this is a legitimate usage of late static binding and is not currently supported. I hope it will be fixed/supported in the final version of PHP 5.3.
I believe that this feature holds a lot of potential, for example you should check Joshua Thompson’s very interesting post: Return to Prototype Based Programming in PHP.
Posted in
content rss

November 15th, 2007 at 4:18 pm
[...] Hodicska has posted part two of his look at the upcoming PHP 5.3 release. In his previous post, he looked at namespacing, but in [...]
November 16th, 2007 at 12:48 pm
Awesome!
I always learn something new.
The other day I fretted myself because I couldn’t solve the ‘Inherit static methods’ problem when I wanted to create a ‘global’
-like stuff.public static function GetInstance(){ return new self(); }
So this is what the coders’ nation calls “Late Static Binding”, eh?
Sweeeeeet.
November 17th, 2007 at 11:25 pm
[...] the first two parts of this series I wrote about namaspaces and late static binding. In this part I will cover mysqlnd (MySQL native driver for PHP), which is also a really cool [...]
November 21st, 2007 at 1:23 am
imho the current 5.3 implementation is right, no need to change. have a look at “other”
oo languages to compare things. solve your problem this way:
{
public static function findByPk($id, $calledClass = null)
{
if ($calledClass === null) {
$calledClass = get_called_class();
}
// The magic remains...
}
}
class Blog extends ActiveRecord
{
public static function findByPk($id)
{
// We want to log something.
// Then the parent should do the magic.
parent::findByPk($id, __CLASS__);
}
}
Blog::findByPk(1);
————————-
regards,
Peter
November 21st, 2007 at 2:07 am
Maybe you should look at prado framework ? They’re already doing something like that for activerecord.
November 21st, 2007 at 8:14 am
@Peter: of course this workaround works, but in my view this is a hack. When you use parent in your code you generally want to extend the parent class. But in this case if you use parent the code in the parent class works in a different way.
November 21st, 2007 at 10:41 pm
@Felho: I agree but I think we have to accept that PHP will never be a true OO language. I’m looking for ways to keep general/common code in parent classes and more specialized code in subclasses what this hack does. So I don’t have to write duplicate code in subclasses. That’s more important to me than true OO principles. But you are right.
November 24th, 2007 at 8:04 pm
[...] What is new in PHP 5.3 – part 2 (0 visite) [...]
November 26th, 2007 at 8:53 am
@peter: In Your example you can no longer ‘correctly’ extend Blog without again rewriting the findByPK method.
So like I have been maintaining, you are just delaying the inevitable.
@everyone: I have just posted a few separate patches that will allow this to be properly worked around. You can read the details at: http://www.ds-o.com/archives/68-Late-Static-Binding-Changes-to-parent.html
February 27th, 2008 at 8:33 pm
Why not make “self” late binding?
March 14th, 2008 at 8:27 pm
it seems like e very good web site but my English is not good. It would be great if it might be availible in other languages too. Thanks.
March 16th, 2008 at 3:50 am
[...] 1: Namespaces Part 2: Late Static Binding Part 3: mysqlnd Part 4: OpenID support, callStatic, user.ini, XSLT profiling and more. Posted [...]
March 16th, 2008 at 3:52 am
[...] 1: Namespaces Part 2: Late Static Binding Part 3: mysqlnd Part 4: OpenID support, callStatic, user.ini, XSLT profiling and more. Posted [...]
April 3rd, 2008 at 10:42 pm
Simple, declare method
findByPkasfinaland be happy!In many cases this dont solve the problem, but in ActiveRecord implementation this work well, because it dont make sense overwrite basic methods of ActiveRecord class.
April 10th, 2008 at 1:01 pm
[...] What is new in PHP 5.3 – part 2: late static binding [...]
April 13th, 2008 at 2:29 am
[...] vi algumas pessoas reportando um problema com Late Static Binding que, do meu ponto de vista, é facilmente resolvido da seguinte [...]
September 7th, 2008 at 8:33 am
[...] Late static binding [...]
September 13th, 2008 at 1:50 pm
[...] possible (the magic function __call – equivalent to method_missing in Ruby) and something called late-static binding which is only available in PHP 5.3. __call allows dynamic method invocation and late-static binding [...]
April 5th, 2009 at 5:47 pm
This advice is really going to help, thanks.
January 29th, 2010 at 6:35 pm
I think you may have a security problem – visitors to this page are being redirected to some worrying Russian site. It looks like some dodgy Javascript has been injected at the top of the page.
April 19th, 2010 at 5:56 pm
[...] was only possible with dirty hacks, some of which involving eval(). But in php 5.3 the concept of Late Static Binding was introduced. With that, our problem is gone with only a few code edits.. In the GetInstance [...]
April 19th, 2010 at 5:58 pm
Late Static Binding also proves a great solution for the singleton and inheritance problem prior to php 5.3. Great article! Thanks!
June 20th, 2010 at 7:42 pm
[...] Page dédiée au Late State Binding [...]