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

у меня есть общая проблема с этим случаем использования: у меня есть класс A. Этот класс имеет неабстрактный метод doStuffCallback() что может быть переопределен, но это не обязательно для каждого подкласса. Но: я хочу убедиться, что если метод переопределен, подкласс-метод должен вызвать метод parents.

пример:

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

поскольку переопределенный метод делает то же самое, было бы очень некрасиво определить два метода для одной и той же ответственности и частного helper-метод, который вызывает оба. Вот так:

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 принудительно переопределить методы для вызова метода parents?

4 ответов


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

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


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

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

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


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

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


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

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

поэтому в основном я бы отметил как "окончательную" функцию, которую вы хотите заставить код для каждого ребенка, а затем вызвать новую "абстрактную" функцию, чтобы заставить детей реализовать ее. Если вы не хотите форсировать новую "абстрактную" функцию, просто не делайте ее абстрактной.

Edit : это в основном ответ @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');

или заменить расширение на magic methods _ _ call и т. д. https://github.com/StagnantIce/php_extend_magic/blob/master/AExtendClass.php