OOP (PHP) — принудительно вызывать переопределенный метод в соответствии с родительским методом

У меня есть общая проблема с этим вариантом использования: у меня есть класс 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 способ заставить переопределенные методы вызывать метод родителей?

7

Решение

Нет. В PHP нет такой языковой функции; это ограничение невозможно в большинстве языков подтипа -OO.

Вместо этого программы должны полагаться на явные контракты на документацию; и, надеюсь, модульное тестирование для обеспечения соответствия.


Охрана также может быть применена таким образом, чтобы в некоторый момент времени, когда метод родительского класса использовался, он мог выдать исключение, если «текущее состояние» недопустимо (например, такой и такой метод не был вызван еще). Это также можно сделать более явным, сделав подкласс необходимым для вызова (как определено в контракте на документацию) какого-то специального метода, а не просто переопределенного супер-метода. Тем не менее, это за пределами любой системы типов.

В то время как self:: объем мог использоваться (например, вызывать не переопределенный метод, который вызывает переопределенный метод), это потребует дополнительной магии (например, некоторое состояние стека), чтобы избежать бесконечных циклов рекурсии; и было бы так же легко случайно пропустить использование.

Я рекомендую вызывать (приватный) метод, который вызывает этот «возможно переопределенный» метод в зависимости от применяемой логики, как показано в примере (хотя, мы надеемся, с более конкретными задачами). Тогда (защищенный) переопределенный метод не ожидается или не требует обработки какой-либо специальной логики; и при этом это не предназначено, чтобы быть вызванным непосредственно вне контекста, установленного родительским классом — это — только то, что это в настоящее время утверждает, что это, специальный обратный вызов.

6

Другие решения

Я склонен не соглашаться с «Это очень уродливо». Это стандартный способ обработки этого варианта использования и вариант Шаблон Метод Шаблон.

Теперь я просто догадываюсь, потому что вы не предоставили реального примера, но если вы скажете, что два метода «делают одно и то же», возможно, что-то не так с вашим дизайном. Если они делают то же самое, зачем вызывать родительскую реализацию, если подкласс делает то же самое по-другому? Для меня это звучит как метод на самом деле больше чем одно и вы можете разбить его на несколько частей, которые могут быть переопределены по отдельности (или нет, а затем сделать их частными или окончательными).

3

Я знаю, что это старая тема, но я задавал себе тот же вопрос, и я сделал следующее:

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, но более конкретный с вашим примером.

0

Нет, вы можете получить доступ, вы можете использовать метод для родителя, как это

<?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

-2
По вопросам рекламы [email protected]