• 11 . 08 . 10
  • Describing a slight inconsistency in PHP 5.3’s use of the static keyword and how it can affect late-static binding.

  • Tags

    , , ,

  • StumbleUpon

Subtle Behaviour of The Static Keyword in PHP 5.3

Version 5.3 of PHP added a new, very useful and long-overdue feature allowing for late-static binding using the ‘static’ keyword instead of the ‘self’ keyword. The PHP manual has a good explanation of the difference. However, there is a subtle behaviour that I certainly hadn’t anticipated and might catch you out.

A typical use-case of the new syntax is to lazy-load static variables in inherited child classes, which offers you the choice of avoiding the overhead of object-instantiation to provide class differentiation. Unfortunately, it is not quite as straightforward as you might think. Consider the following piece of code:

class BaseClass {

	static $_value = null;

	public static function getValue() {
		if (null === static::$_value) {
			static::$_value = get_called_class();
		}
		return static::$_value;
	}
}

class ChildAClass extends BaseClass {}

echo BaseClass::getValue() . "\n";
echo ChildAClass::getValue() . "\n";

What’s going on here then? When I look at that piece of code, I expect the output to be:

BaseClass
ChildAClass

Instead, it appears the call to ChildAClass::getValue() fails the conditional test and returns the static value of BaseClass, giving the following output:

BaseClass
BaseClass

Not very helpful. How can we work around this? The answer is to ensure you declare the static variable in each of your child classes as well as the parent. It’s straightforward enough, but a pain to remember every time. The following example demonstrates:

class ChildBClass extends BaseClass {

	static $_value = null;
}

echo BaseClass::getValue() . "\n";
echo ChildBClass::getValue() . "\n";
BaseClass
ChildBClass

So it appears (at least for PHP 5.3.3 (OS X)), that static only really means static if you declare it yourself each time. This might be expected behaviour, but I consider it a bug, and it can certainly lead to hard to debug situations. It doesn’t seem to be documented clearly in any standard location that I could find.

Short story – if you are looking to lazily-populate static variables using the new syntax, be sure to declare the variables in all of the child classes you are going to use!