繁体   English   中英

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

[英]OOP (PHP) - Force overridden method to call according parent-method

我对这个用例有一个普遍的问题:我有一个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
    }
}

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

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

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

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


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

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

所以基本上我会将你希望强制每个孩子的代码的函数标记为“final”,然后调用一个新的“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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM