У меня есть общая проблема с этим вариантом использования: у меня есть класс A
, Этот класс имеет неабстрактный метод doStuffCallback()
который может быть переопределен, но это не обязательно для каждого подкласса. Но: я хочу убедиться, что если метод переопределен, метод подкласса должен вызывать метод parent.
Пример:
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
protected function doStuffCallback() {
// IMPORTANT CODE HERE
}
}
class B extends A {
protected function doStuffCallback() {
parent::doStuffCallback(); // I want to enforce this because the parents method code is important
// ALSO IMPORTANT CODE
}
}
Поскольку переопределенный метод делает то же самое, было бы очень уродливо определять два метода с одинаковой ответственностью и частный вспомогательный метод, который вызывает оба. Как это:
abstract class A {
private function doStuff() {
$this->callDoStuffCallback();
}
private function callDoStuffCallback() {
$this->internalDoStuffCallback();
$this->doStuffCallback();
// This is VERY ugly
}
private function internalDoStuffCallback() {
// IMPORTANT CODE HERE
}
protected function doStuffCallback() {}
}
class B extends A {
protected function doStuffCallback() {
// IMPORTANT CODE
}
}
Это действительно безобразно и кропотливо. Итак, мой вопрос: Есть ли в PHP способ заставить переопределенные методы вызывать метод родителей?
Нет. В PHP нет такой языковой функции; это ограничение невозможно в большинстве языков подтипа -OO.
Вместо этого программы должны полагаться на явные контракты на документацию; и, надеюсь, модульное тестирование для обеспечения соответствия.
Охрана также может быть применена таким образом, чтобы в некоторый момент времени, когда метод родительского класса использовался, он мог выдать исключение, если «текущее состояние» недопустимо (например, такой и такой метод не был вызван еще). Это также можно сделать более явным, сделав подкласс необходимым для вызова (как определено в контракте на документацию) какого-то специального метода, а не просто переопределенного супер-метода. Тем не менее, это за пределами любой системы типов.
В то время как self::
объем мог использоваться (например, вызывать не переопределенный метод, который вызывает переопределенный метод), это потребует дополнительной магии (например, некоторое состояние стека), чтобы избежать бесконечных циклов рекурсии; и было бы так же легко случайно пропустить использование.
Я рекомендую вызывать (приватный) метод, который вызывает этот «возможно переопределенный» метод в зависимости от применяемой логики, как показано в примере (хотя, мы надеемся, с более конкретными задачами). Тогда (защищенный) переопределенный метод не ожидается или не требует обработки какой-либо специальной логики; и при этом это не предназначено, чтобы быть вызванным непосредственно вне контекста, установленного родительским классом — это — только то, что это в настоящее время утверждает, что это, специальный обратный вызов.
Я склонен не соглашаться с «Это очень уродливо». Это стандартный способ обработки этого варианта использования и вариант Шаблон Метод Шаблон.
Теперь я просто догадываюсь, потому что вы не предоставили реального примера, но если вы скажете, что два метода «делают одно и то же», возможно, что-то не так с вашим дизайном. Если они делают то же самое, зачем вызывать родительскую реализацию, если подкласс делает то же самое по-другому? Для меня это звучит как метод на самом деле больше чем одно и вы можете разбить его на несколько частей, которые могут быть переопределены по отдельности (или нет, а затем сделать их частными или окончательными).
Я знаю, что это старая тема, но я задавал себе тот же вопрос, и я сделал следующее:
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
final protected function doStuffCallback() {
// IMPORTANT CODE HERE
$this->callNewFunction();
}
abstract protected function callNewFunction();
}
class B extends A {
protected function callNewFunction() {
// ALSO IMPORTANT CODE
}
}
Таким образом, в основном я хотел бы отметить как «конечную» функцию, которую вы хотите заставить код для каждого дочернего элемента, а затем вызвать новую «абстрактную» функцию, чтобы заставить дочерние элементы реализовать ее. Если вы не хотите использовать новую функцию «Abstract», просто не делайте ее абстрактной.
Изменить: Это в основном ответ @Fabian Schmengler, но более конкретный с вашим примером.
Нет, вы можете получить доступ, вы можете использовать метод для родителя, как это
<?php
class A {
function s1($p1) {
echo 's1: '.$p1;
}
}
class B extends A {
public function callParent($method, $p1) {
parent::$method($p1);
}
}
$b = new B();
$b->callParent('s1', 'param1');
или замените расширение на магические методы __call и т. д. https://github.com/StagnantIce/php_extend_magic/blob/master/AExtendClass.php