Skip to content

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.

Consider the following code:

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 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.

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

The catch-22, this is only good if you are using PHP 5.3 or higher. If you’re using a prior version, you should strongly consider upgrading.

Legacy PHP < 5.3

There is 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, albeit with some performance overhead.

We can craft a dynamic helper method for resolving the correct static field with Reflection.

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!'