You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP多级继承最佳实践:BC类抛异常强制重写是否合理?

问题:子类强制重写方法的实现是否符合最佳实践?

在架构开发过程中,我产生了一个疑问:当前的实现是否符合最佳实践?

现有抽象类A:

abstract class A {

    protected mixed $object;

    public function __construct() {

        $this->loadObject()
             ->fuc1();
    }

    abstract protected function loadObject(): self;
    abstract public function fuc1(): bool;
    abstract public function fuc3(): iterable;
}

由于类B和C存在相同方法,我为它们创建了基类BC,代码如下:

class BC extends A {

    protected string $x;
    protected string $y;

    protected function loadObject(): self {
         throw new \Exception('Child must implement loadObject');
    }
    public function fuc1(): bool {
         //Some Codes
    }
    public function fuc3(): iterable {
        //Some Codes
    }
    
}

类B和类C的实现如下:

class B extends BC {

    protected function loadObject(): self {
        $this->object = new SomeObject();
        return $this;
    }
}

class C extends BC {

    protected function loadObject(): self {
        $this->object = new SomeObject2();
        return $this;
    }
}

同时,无法将loadObject方法移至BC类,因为可能有类D直接继承A;若依赖接口实现,又担心开发者忘记让B/C实现接口导致A类出现问题。请问这种通过在BC类中抛出异常强制子类重写loadObject方法的方式是否为良好实践?


回答

这种通过运行时抛异常强制子类重写方法的方式不是良好实践,核心问题在于:错误只会在代码运行时暴露,无法在编写或静态检查阶段提前发现,很容易导致开发者遗漏实现,等到线上或测试时才触发报错,排查成本高。

更规范的解决方案是把BC也声明为抽象类,让loadObject继续保持抽象方法:

abstract class BC extends A {
    protected string $x;
    protected string $y;

    // 保持抽象方法,强制子类必须实现
    abstract protected function loadObject(): self;

    public function fuc1(): bool {
         // Some Codes
    }
    public function fuc3(): iterable {
        // Some Codes
    }
}

这个方案的优势:

  • 约束前置:任何继承BC的子类(比如B、C)如果不实现loadObject,在代码编写阶段(或IDE静态检查时)就会直接报错,从根源上避免遗漏实现的问题。
  • 不影响原有场景:类D依然可以直接继承抽象类A,不受BC的影响,完全符合需求。
  • 符合面向对象设计原则:抽象类的核心作用之一就是定义子类必须遵守的契约,这种方式比运行时抛异常更贴合抽象类的设计初衷。

内容的提问来源于stack exchange,提问作者sajjad rezaei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:15:41