- 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.
- StumbleUpon
- TwitterTweet
- Facebook
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:
[php]
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";
[/php]
What’s going on here then? When I look at that piece of code, I expect the output to be:
[php]
BaseClass
ChildAClass
[/php]
Instead, it appears the call to ChildAClass::getValue() fails the conditional test and returns the static value of BaseClass, giving the following output:
[php]
BaseClass
BaseClass
[/php]
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:
[php]
class ChildBClass extends BaseClass {
static $_value = null;
}
echo BaseClass::getValue() . "\n";
echo ChildBClass::getValue() . "\n";
[/php]
[php]
BaseClass
ChildBClass
[/php]
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!
Stoat – Where?: Subtle Behaviour of The Static Keyword in PHP 5.3 http://bit.ly/bpoCY8
This comment was originally posted on Twitter
Hi, I realize it’s been a while since you posted this, but I’ve run into a similar quirk with static methods and am curious if you’ve seen it. Consider:
Class leg {
Public static method walk () {
Echo “walking”;
} }
Class foot extends leg {
Public function step () {
Return static::walk();
}
}
Class body {
Public function move () {
foot::step()
}
}
$person = new body;
$person->move();
Perhaps I’m doing something wrong, but when I try this I get an error saying body::walk doesn’t exist. It appears the LSB is expecting the method to be part of body, when it shouldn’t think it would be outside of the scope of leg and foot. I’ve been looking for a while now to find an answer and your post is the only thing close. Is this a known bug or does it work the same for you? I’m at a loss. Thanks 🙂
Hi,
When you use the static keyword, PHP waits until runtime to see what class the method should be called on. Because you call foot::step() inside body->move(), when the step() function is executed, the current context is foot, so static is bound to foot. In this instance, you actually want self::walk() inside foot::step().
It is a similar case to the one I outline above. Basically, the static:: operator doesn’t fall through to a parental scope, if nothing matches in the current scope.
Hope that helps!
Jamie.