Etienne Kneuss

home » news » Late Static Bindings Explained

SPL Datastructures

The Standard PHP Library was recently completed by a couple of data structures, namely heaps and doubly linked lists. You can find more information about those on
php.net/spl.datastructures

Feeds available

You can read colder.ch directly from the rss/atom feeds:
rss general RSS (general)
rss php RSS (PHP)
atom general Atom (general)
atom php Atom (PHP)

New design : Clearblue

I've made a new skin using the same design with blue colors: Clearblue. Check it out

New website

As you can see, the website has changed completely. I've re-designed everything using different types of technology to give an overall improvement. Take a look in the news section for detailed information.

Late Static Bindings Explained The 24th of August 2007 @ 17:38

Table of Content

  1. Introduction
  2. What is Late Static Bindings
  3. Examples
  4. Edge Cases

Introduction

Late Static Binding (LSB, yes, not LSD) is an OO feature that is meant to be implemented in PHP 6, and maybe even backported to PHP 5. This article will describe what LSB is, what problems it's supposed to solve and how.

Update: LSB finally got commited in HEAD, this article now describes the way it currently works if you try out a snapshot. The behavior is supposed to remain the same in the future.

What is Late Static Binding

Currently, 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:

<?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(); // A ?>

LSB tries to solve that problem by introducing a keyword that references the class that was initially called at runtime. Basically, a keyword that would allow you to reference B from test() in the previous example. It was decided not to introduce a new keyword but rather use static that was already reserved.

<?php class A {     public static function who() {         echo __CLASS__;     }     public static function test() {         static::who();     } } class B extends A {     public static function who() {         echo __CLASS__;     } } B::test(); // B ?>

Some people describe static:: as the $this-> resolution for static calls, this is not true as $this-> follows the rules of inheritance while static:: doesn't.

Examples

Most basic example:

<?php class TestClass {    protected static function who() {         echo __CLASS__."\n";    }    public static function test() {        return static::who();    } } class ChildClass1 extends TestClass {    protected static function who() {         echo __CLASS__."\n";    } } class ChildClass2 extends TestClass {} TestClass::test();   // TestClass ChildClass1::test(); // ChildClass1 ChildClass2::test(); // TestClass ?>

It can also be used in a non-static context:

<?php class TestChild extends TestParent {     public function __construct() {         static::who();     }     public function test() {         $o = new TestParent();     }     public static function who() {         echo __CLASS__."\n";     } } class TestParent {     public function __construct() {         static::who();     }     public static function who() {         echo __CLASS__."\n";     } } $o = new TestChild; // TestChild $o->test();         //TestParent ?>

Fully resolved static calls with no fall backs will break the resolution of the late static binding.

<?php class A {     public static function foo() {         static::who();     }              public static function who() {         echo __CLASS__."\n";     } } class B extends A {     public static function test() {         A::foo();     }     public static function who() {         echo __CLASS__."\n";     } } B::test(); // A ?>

Edge Cases

Because of the way scopes are traversed, and that no breaks are enforced for internal hooks, it means that static:: would work the same way even with a fallback that occurs on them, i.e. __get(), __set(), ...

<?php class A {    protected static function who() {         echo __CLASS__."\n";    }    public function __get($var) {        return static::who();    } } class B extends A {    protected static function who() {         echo __CLASS__."\n";    } } $b = new B; $b->foo; // B ?>

The same principle applies to handlers, as long as they are defined and called within valid scopes.

Comments

24.08.2007 #1 carl

YES! LSB is definately something I've been missing in PHP5 since the beginning. Of course I didn't know of the term Late Static Binding until now... Great work!

25.08.2007 #2 No Thx

Is there some way to simulate this in PHP 5?
I was thinking about something like this:

<?php
class parentClass {
public function normalTest() {
// I guess this works?
$this->lsbSim('who');
}
public static function staticTest() {
// $this->lsbSim('who'); // Won't work, $this has no meaning in a static method.
// self::lsbSim('who'); // Won't work because lsbSim() is not a static method and can not be resolved with self::.
}
protected function lsbSim($func, array $args = array()) {
return call_user_func_array(array(get_class($this), $func), $args);
}
public static function who() {
echo __CLASS__;
}
}

class childClass extends parentClass {
public static function who() {
echo __CLASS__;
}
}

$parentClass = new parentClass;
$parentClass->normalTest(); // Outputs: parentClass
$childClass = new childClass;
$childClass->normalTest(); // Outputs: childClass
?>

So this won't work inside static methods (see parentClass::staticTest()), and every class has to be a descendant of parentClass. But for the rest, I guess this works fine?

06.09.2007 #3 gqksltszkpegvu

What makes this "late binding" and "static binding?"

07.09.2007 #4 no.thanks

You can also emulate this by passing __CLASS__ into protected functions, and using 'new $cls()' or call_user_func[_array] with the passed-in class.

07.09.2007 #5 doughill

I NEEEEED this right now, it would solve a few cludges I have going on very elegantly.

10.09.2007 #6 ctx2002

late static bind? this team sound confuse. how comes static method / function can be later bound? is not static method bound to class?

13.09.2007 #7 colder

The term "late static bindings" came up with an internal perspective in mind:

Internally, a method definition contains the class in which it's defined. When you extend a class, methods from the parent class get merged with the new methods in the child class, but the methods from the parent class still contain the reference to the parent class. Hence, when you use self:: for example, the class reference in the method definition is used, thus calling the parent class.

"Late binding" comes from the fact that static:: will no more be resolved using the defined class reference but it will rather be computed using runtime information.

"static binding" is relative to the fact that self::foo() calls are described as static (even if they may in fact not be static calls in some cases). The same principle applies with static::

13.12.2007 #8 mjijackson

This is fantastic! Thanks so much for working on the patch Etienne. This small feature will open up a lot of possibilities.

08.02.2008 #9 spam-here-please

Well done Etienne, it's a very handy patch :)

19.03.2008 #10 booboo

And what about overriden static members and "self" resolution to it in non-static inherited methods?

19.03.2008 #11 booboo

Sorry, i mean properties instead of members

14.10.2008 #12 neviedais

Properties are members. And members are properties.

ja som slovak, statny znak je SK.

Add a comment

Username:

Spam Challenge: 1+10=?

Comment: