TL;DR: As of PHP 7, you can. Before then, you could define abstract static
on trait
, but internals deemed it bad practice.
Strictly, abstract
means sub-class must implement, and static
means code for this specific class only. Taken together, abstract static
means "sub-class must implement code for this specific class only". Totally orthogonal concepts.
But... PHP 5.3+ supports static inheritance thanks to LSB. So we actually open that definition up a bit: self
takes the former definition of static, while static
becomes "code for this specific class or any of its sub-classes". The new definition of abstract static
is "sub-class must implement code for this specific class or any of its sub-classes". This can lead some folks, who think of static
in the strict sense, to confusion. See for example bug #53081.
What makes trait
so special to elicit this warning? Well, take a look at the engine code that implements the notice:
if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
}
That code says the only place an abstract static
is allowed is within an interface
. It's not unique to traits, it's unique to the definition of abstract static
. Why? Well, notice there's a slight corner case in our definition:
sub-class must implement code for this specific class or any of its sub-classes
With this code:
abstract class Foo {
abstract public static function get();
}
That definition means I should be able to call Foo::get
. After all Foo
is a class (see that keyword "class" there) and in the strict definition, get
is meant to be implemented in that class Foo
. But clearly that makes no sense, because well, we're back to the orthogonality of strict static.
If you try it in PHP, you get the only rationale response possible:
Cannot call abstract method Foo::get()
So because PHP added static inheritance, it has to deal with these corner cases. Such is the nature of features. Some other languages (C#, Java, etc.) don't have this problem, because they adopt the strict definition and simply don't allow abstract static
. To get rid of this corner case, and simplify the engine, we may enforce this "abstract static only in interface" rule in the future. Hence, E_STRICT
.
I would use a service delegate to solve the problem:
I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.
trait MyTrait
{
public function doSomethingWithSetting() {
$service = new MyService($this);
return $service->doSomethingWithSetting();
}
}
class MyService
{
public function __construct(MyInterface $object) {
$this->object = $object;
}
public function doSomethingWithSetting() {
$setting = $this->object->getSetting();
return $setting;
}
}
Feels a bit Rube Goldberg though. Probably would look at the motivation for statics and consider refactoring them out.
error_reporting
setting? The above should give rise to anE_STRICT
error. – eggyalstatic
method in the first place? It doesn't make any difference to the trait whether it calls astatic
method or not, and since you're actually explicitly calling it from a non-static method, there's no reason to forcegetSetting
to bestatic
. That leaves the implementor less freedom, for example to return settings based on instance variables. – deceze