Late static binding workaround prior to PHP 5.3

A workaround for binding to the intended static scope without using the static:: operator introduced in PHP 5.3.

The Issue

When calling a parent method, we often want dynamic binding to occur so that any method calls and member references made in this parent method will be looked up starting in the true class of the object being invoked and then in the inheritance tree. This is polymorphic behaviour that we are accustomed to. In PHP, dynamic (late) binding happens implicitly for object methods and object members, but not implicitly for static methods & members  – the scope where the calling method is defined is where the lookup begins in the inheritance chain.

An example,


abstract class Action {
  protected static $message = 'override me!';

  public function run() { echo self::$message; }
}

class AwesomeAction extends Action {
  protected static $message = 'Yeahhhhhhhh!';
}

$action = new AwesomeAction;
$action->run();

Running this code will output “override me!” Not quite the awesome action that we were hoping for 🙁

The Fix

Now, if we want static bindings to be dynamic and behave in the same way that $this does, PHP 5.3 does have a feature for binding to the intended static scope. To use it we change the base method run() to use the static:: resolution operator instead of self:: resolution operator.

The catch22, this is only good if you are using PHP 5.3 or higher. If you’re stuck on an earlier version for whatever the reason, the static:: operator is not available to you. At the cost of some performance, I now show a way to dynamically bind to the intended static scope and access the intended static member that is backwards compatible with older PHP5.x versions.


//PHP 5.3 late static bindings fix
public function run() { echo static::$message; }

//A workaround for PHP prior to 5.3
protected function self($member) {
  //Reflect on this class
  $class = new ReflectionClass($this);

  return $class->getStaticPropertyValue($member);
}

And of course, the example revisited with the “dynamic” self method,


abstract class Action {
  public static $message = 'override me!';

  public function run() { echo $this->self('message'); }

  protected function self($member) {
    $class = new ReflectionClass($this);
    return $class->getProperty($member); 
  }

}

class AwesomeAction extends Action {
  public static $message = 'Yeahhhhhhhh!';
}

$action = new AwesomeAction;
$action->run(); //Will now output 'Yeahhhhhhhh!'