抽象类的abstract方法必须在子类中以同名、同参数、同或更宽访问权限实现,否则报致命错误;构造方法不受约束,非抽象方法可选重写,静态方法重写需用static::支持后期绑定。

抽象类方法必须在子类中实现
PHP 抽象类里的 abstract 方法,不能有函数体,子类继承后**必须用同名、同参数、同可见性(或更宽)的方法覆盖实现**,否则会报致命错误:Fatal error: Class XXX contains abstract method ... and must therefore be declared abstract or implement the remaining methods。
常见错误是:子类写了同名方法但参数个数/类型不一致、加了默认值导致签名不匹配、或用了 private 降低可见性。
- 抽象方法声明为
protected function doSomething($a, $b),子类必须写protected function doSomething($a, $b)(或public),不能少参数,也不能多加可选参数(除非父类也允许) - PHP 8.0+ 对参数类型协变支持更好,但基础签名仍需严格一致;若父类是
function handle(string $x),子类不能写function handle(int $x) - 返回类型是逆变的(PHP 7.4+),子类可声明更具体的返回类型,如父类
: object,子类可写: User
子类重写时可以扩展访问权限
抽象方法在父类中声明为 protected,子类实现时可用 public,这是合法且常见的做法——比如框架基类把核心逻辑设为 protected abstract,留给子类公开调用入口。
但反过来不行:public abstract 方法不能在子类中降级为 protected 或 private,会触发 Access level to XXX::yyy must be public (as in class ZZZ) 错误。
立即学习“PHP免费学习笔记(深入)”;
- 允许:
abstract protected function run();→ 子类public function run() { ... } - 禁止:
abstract public function init();→ 子类protected function init() { ... } - 构造方法
__construct()不受抽象约束,子类可自由定义,但若需调用父类初始化逻辑,记得手动parent::__construct()
非抽象方法也能被重写,但不是强制的
抽象类里也可以包含具体方法(非 abstract),这些方法默认会被继承,子类可选择是否重写。重写规则和普通继承一致:函数名、参数列表需兼容,访问控制不能更严格。
注意:如果父类方法用了 final,子类就无法重写,会报 Cannot override final method。
- 父类有
public function log($msg) { echo "[LOG] $msg"; },子类可写public function log($msg) { error_log($msg); } - 若父类是
final public function getConfig() { ... },子类中任何同名定义都会直接报错 - 静态方法也能被重写,但
self::在父类中仍指向父类,要用static::实现后期静态绑定
用 get_class_methods() 检查实际可用方法
抽象类本身不能实例化,但子类实例化后,有时会疑惑“为什么某个方法调不到”——可能是因为该方法仍是 abstract、没被实现,或被意外覆盖出错。用 get_class_methods() 可快速验证:
var_dump(get_class_methods(new ChildClass()));
输出里不出现抽象方法名,说明它已被正确实现;若出现,代表子类没提供对应方法体(或命名/大小写有误,PHP 是大小写敏感的)。
另一个易忽略点:抽象类中的 __call() 和 __callStatic() 不会自动代理抽象方法调用——它们只捕获未定义方法,对声明了但未实现的抽象方法无效,错误会在实例化时就抛出,不会等到运行时。
真正麻烦的是带泛型风格的抽象模板(比如 PHP 8.2+ 的 abstract class Repository),此时重写不仅要看方法签名,还要确保子类指定了正确的类型实参,否则类型推导会失败,IDE 和静态分析工具容易静默忽略这点。










