簡體   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