Ответ 1
TL; DR: вы можете определить abstract static
на trait
s, но внутренняя среда считает это плохой практикой и может удалить ее в будущем.
У меня не было большого количества кофеина, но я дам ему трещину.
Строго говоря, abstract
означает, что должен выполняться подкласс, а static
означает код только для этого конкретного класса. В совокупности abstract static
означает, что "подкласс должен реализовывать только код для этого конкретного класса". Полностью ортогональные понятия.
Но... PHP 5.3+ поддерживает статическое наследование благодаря LSB. Таким образом, мы фактически открываем это определение немного: self
принимает прежнее определение static, а static
становится "кодом для этого конкретного класса или любого из его подклассов". Новое определение abstract static
- это "подкласс" должен реализовать код для этого конкретного класса или любого из его подклассов ". Это может привести некоторых людей, которые думают о static
в строгом смысле, к путанице. См. Например ошибка # 53081.
Что делает trait
настолько особенным, чтобы вызвать это предупреждение? Хорошо, посмотрите на код двигателя, который реализует уведомление:
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);
}
В этом коде говорится, что единственное место, где разрешен abstract static
, находится внутри interface
. Он не уникален для черт, он уникален для определения abstract static
. Зачем? Хорошо, обратите внимание на небольшой угловой случай в нашем определении:
подкласс должен реализовать код для этого конкретного класса или любого из его подклассов
С помощью этого кода:
abstract class Foo {
abstract public static function get();
}
Это определение означает, что я должен был бы называть Foo::get
. В конце концов, Foo
является классом (см. Это ключевое слово "класс" ) и в строгом определении get
предполагается реализовать в этом классе Foo
. Но ясно, что это не имеет никакого смысла, потому что хорошо, мы вернулись к ортогональности строгой статики.
Если вы попробуете его на PHP, вы получите единственное обоснование:
Невозможно вызвать абстрактный метод Foo:: get()
Итак, поскольку PHP добавил статическое наследование, он должен иметь дело с этими угловыми случаями. Такова природа особенностей. Некоторые другие языки (С#, Java и т.д.) Не имеют этой проблемы, поскольку они принимают строгое определение и просто не допускать abstract static
. Чтобы избавиться от этого углового случая и упростить двигатель, в будущем мы можем применить это правило "абстрактное статическое только в интерфейсе". Следовательно, E_STRICT
.
Я бы использовал делегат службы для решения проблемы:
У меня есть общий метод, который я хочу использовать в нескольких классах. Этот общий метод основан на статическом методе, который должен быть определен извне в общий код.
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;
}
}
Чувствует себя немного Рубе Голдбергом. Вероятно, он бы посмотрел на мотивацию для статики и подумал о том, чтобы реорганизовать их.