coderholic

Faking late static binding in PHP

PHP 5.3 brings lots of long awaited features to the language, including closures, late static binding and namespaces. Unfortunately 5.3 still isn't widely available, so some of us are stuck with older version of the language that lack these great new features.

One feature I miss all the time is late static binding, or LSB. The lack of LSB means that you can't tell tell which class in your class hierarchy was invoked when calling a static method. Here's a simple example:

class class0 {
  public static function getName() {
      echo __CLASS__ . "\n";
  }
}

class class1 extends class0 {}

class class2 extends class1 {}

class0::getName(); // -> "class0"
class1::getName(); // -> "class0"
class2::getName(); // -> "class0"

Notice that all three method calls output "class0", the name of the base class. There is no way to tell which class the static method was called on, and in some situations that is information we need to know.

So what can we do? One obvious solution is to re-implement the method in every subclass. This doesn't pose much of a problem for a method as simple as the one in our example, but in reality our method is likely to be much more complex, and implementing it in every subclass will lead to lots of duplication. If we ever need to make changes to the method then changes will need to be made to every subclass too. Not fun!

And alternative solution is to have every subclass invoke the parent method, passing in the class name (or whatever variable we're interested in). It requires only a couple of extra lines per subclass, rather than repeating the whole method. Any changes now only need to be made in one place. Here's the code:

class class0 {
  public static function getName($class = __CLASS__) {
      echo "$class\n";
  }
}

class class1 extends class0 {
  public static function getName($class = __CLASS__) {
      return parent::getName($class);
  }
}

class class2 extends class1 {
  public static function getName($class = __CLASS__) {
      return parent::getName($class);
  }
}

class0::getName(); // -> "class0"
class1::getName(); // -> "class1"
class2::getName(); // -> "class2"

In PHP5.3 we can use the new get_called_class(), so the code becomes much cleaner:

class class0 {
  public static function getName() {
      echo get_called_class() . "\n";
  }
}

class class1 extends class0 {}

class class2 extends class1 {}

class0::getName(); // -> "class0"
class1::getName(); // -> "class1"
class2::getName(); // -> "class2"
Posted on 18 Nov 2009
If you enjoyed reading this post you might want to follow @coderholic on twitter or browse though the full blog archive.