Как заставить реализацию защищенной статической функции
Я пытаюсь написать абстрактный класс (или интерфейс), который заставляет расширяющий класс реализовать защищенную статическую функцию. Но это невозможно ни с абстрактным классом, ни с интерфейсом.
Ошибки:
- статические функции не должны быть абстрактными
- тип доступа для членов интерфейса должен быть опущен
Есть идеи, как этого добиться?
ОБНОВИТЬ
Цель в основном состоит в том, чтобы вызывать публичную функцию статически. Таким образом, не нужно создавать экземпляр класса. Также необязательно делать _doSpecificStuff() вызываемым из внешнего кода класса.
abstract class Foo
{
public static function doStuff()
{
[generic code]
static::_doSpecificStuff();
}
// sth like that would be nice to have:
abstract static protected function _doSpecificStuff();
}
1 ответ
С теоретической, а также с практической точки зрения, нет необходимости объявлять абстрактный метод статическим.
Существуют абстрактные методы для заполнения дочернего класса пробелом. Обычно это происходит потому, что родительский класс (исходный абстрактный класс) выполняет некоторую общую операцию, но может / должен быть адаптирован к определенным конкретным ситуациям и, таким образом, может заставить дочерние классы реализовывать только эту конкретную переменную часть в общем универсальном алгоритме. Абстрактные методы должны быть пустым местом в более широком алгоритме.
Родительский метод будет вызывать реализации своих абстрактных методов, не зная и не заботясь о том, кто их реализует или как они реализованы:
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Foo
не волнует, кто или что заполняет пробел doSomethingSpecific
, он просто полагается на то, что он там и его подпись, которая abstract
навязывает. Конкретный объект, который реализует этот метод или как он реализует его, является переменной. Это важно и лежит в основе проблемы.
Объявление абстрактного статического метода в этом сценарии довольно бесполезно. Любой статический метод также может быть реализован как нестатический метод, поэтому здесь его нет смысла. Если сам класс должен вызывать абстрактный метод как часть более крупного универсального алгоритма, как описано выше, то нет необходимости в статическом методе.
Таким образом, единственный сценарий, оставшийся для статического метода, - это public static
метод, который можно вызвать из любого места:
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
Дело в том, что, так как abstract class Foo
сама функция не вызывает эту функцию, но эта функция вызывается только из внешнего кода, вы на самом деле не говорите о методе заполнения пустых строк, вы говорите об интерфейсе. Итак, вы должны использовать interface
вместо.
Но даже в этом случае, поскольку вы должны ввести конкретное имя класса в исходном коде, жестко запрограммированное, для интерфейса также нет особого смысла.
Смысл объявления сигнатуры интерфейса или абстрактного метода заключается в том, что вы хотите исправить сигнатуру метода, чтобы любой код мог вызывать этот конкретный метод, не заботясь о том, к какому объекту он обращается, в частности. Но поскольку вам нужно жестко закодировать имя класса, в объекте, к которому вы его вызываете, нет никакой изменчивости. Если вы печатаете Baz::bar()
, вы точно знаете, какой класс вы вызываете, какой метод. Поэтому нет смысла абстрагировать интерфейс / подпись.
Для сравнения:
interface FooInterface {
public function bar();
}
function baz(FooInterface $foo) {
$foo->bar();
}
Функция baz
может опираться на свой аргумент, имеющий bar()
метод из-за объявления интерфейса. Конкретный объект, который реализует метод, не имеет значения и будет отличаться.
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Класс Foo
может рассчитывать на то, что doSomethingSpecific
метод. Конкретный объект, который реализует метод, не имеет значения и будет отличаться.
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
На что именно вы полагаетесь или абстрагируетесь здесь? Вы можете быть чертовски уверен Baz
будет метод bar()
каждый раз, потому что вы вызываете его только в том же жестко закодированном классе. Здесь нет ничего переменного.