OOP(PHP) - 强制重写方法根据父方法调用

Luc*_*ler 9 php oop abstraction

我对这个用例有一个普遍的问题:我有一个班级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
    }
}
Run Code Online (Sandbox Code Playgroud)

因为重写的方法做同样的事情,为同一个责任定义两个方法和调用两个方法的私有帮助方法会非常难看.像这样:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

这真是丑陋和辛苦.所以我的问题:在PHP中是否有办法强制重写方法来调用parents方法?

use*_*740 6

没有.PHP中没有这样的语言功能; 在大多数子类型''''语言中,这种限制是不可能的.

相反,程序必须依赖明确的文档合同; 并希望通过单元测试来确保一致性.


也可以使用防护,使得在某个时刻使用父类的方法时,如果"当前状态"无效,它可能会抛出异常(例如,这样的方法并没有被调用)然而).通过使子类需要调用(如文档合同中所定义)一些特殊方法而不是简单地覆盖超级方法,这也可以更明确.但是,这种情况不属于任何类型的系统.

虽然self::范围可以被使用(如:调用非覆盖方法它调用覆盖方法),这将涉及进一步魔会造成死循环回路(例如,一些堆叠状态.); 并且容易意外地省略使用.

我的建议是调用一个(私有)方法,该方法调用这个"可能被覆盖"的方法与任何适用的逻辑相关,如示例所示(尽管希望有更多任务特定的驯服).然后,不期望或不需要(受保护的)覆盖方法来处理任何特殊逻辑本身; 它也不是直接在父类建立的上下文之外调用 - 它正是它目前声称的,一种特殊的回调.


ane*_*101 5

我知道这是一个老话题,但我问自己同样的问题,我所做的是:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,基本上我会将您希望强制为每个子级执行代码的函数标记为“最终”函数,然后调用一个新的“抽象”函数来强制子级实现它。如果您不想强制使用新的“抽象”功能,只需不要将其抽象化即可。

编辑:这基本上是@Fabian Schmengler 的答案,但更具体地说明您的示例。