One of my colleagues called me out on something I should never do in PHP, that
is using self to reference static variables. I wasn’t aware of the static::
keyword but after learning about the late static binding in PHP I realised that
self:: does not behave the way I assumed in an in an inheritance context, which
can lead to subtle bugs. The risk comes from the fact that self binds to the
class where the method is defined, so subclasses do not override the referenced
static property.
Self is still correct when you want behavior locked to the defining class, but not when you expect subclasses to override the accessed static property.
The difference becomes clear in a simple example.
<?php
class A
{
protected static $count = 5;
protected static $name = 'A';
public static function incSelf()
{
return ++self::$count;
}
public static function incStatic()
{
return ++static::$count;
}
public static function getName()
{
return static::$name;
}
}
class B extends A
{
protected static $count = 12;
protected static $name = 'B';
}
print_r('A::getName(): ' . A::getName() . PHP_EOL);
print_r('A::incSelf(): ' . A::incSelf() . PHP_EOL);
print_r('A::incStatic(): ' . A::incStatic() . PHP_EOL);
print_r(PHP_EOL);
print_r('B::getName(): ' . B::getName() . PHP_EOL);
print_r('B::incSelf(): ' . B::incSelf() . PHP_EOL);
print_r('B::incStatic(): ' . B::incStatic() . PHP_EOL);
The output above shows that:
- Calls through
selfoperate on A’s properties even when invoked from B. - Calls through
staticoperate on the properties of the class that initiated the call.
Late static binding affects both properties and methods, so static::method()
will resolve according to the class that makes the call.