抽象类须用abstract声明且不可实例化;含abstract方法的类必须声明为abstract,而abstract类可无抽象方法;abstract方法无函数体、访问修饰符仅限public/protected;子类必须实现所有abstract方法,否则自身亦为abstract类。

抽象类必须用 abstract 关键字声明,且不能实例化
PHP 中只要类里有至少一个 abstract 方法,整个类就必须加 abstract 声明;反过来,abstract 类可以没有抽象方法(但通常都有)。一旦声明为 abstract,直接 new 它就会报 Fatal error: Cannot instantiate abstract class。
常见错误是:只给方法加了 abstract,却忘了在 class 前加 abstract —— 这会导致解析失败,报 Parse error: syntax error。
- 抽象方法只能有声明,不能有函数体(连空花括号
{}都不允许) - 抽象方法的访问修饰符只能是
public或protected,不能是private - 抽象类可以包含具体方法(非
abstract),这些方法会被子类直接继承并可调用
具体子类继承抽象类时,extends 必须写在 implements 前面
如果子类既要继承抽象父类,又要实现接口,语法顺序强制为:class Child extends Parent implements InterfaceA, InterfaceB。写成 implements 在前会直接报 Parse error。
PHP 8.3 没改变这个语法规则,但它加强了抽象属性的支持:从 8.4 开始才允许 abstract 属性,而 8.3 仍只支持抽象方法。
立即学习“PHP免费学习笔记(深入)”;
- 子类必须实现父类中所有
abstract方法,否则自身也会变成抽象类(或触发Compile Error: Class must implement all abstract methods) - 方法签名必须兼容:参数数量、类型(含协变/逆变)、返回类型都不能违反 LSP 原则
- 若父类构造函数有参数,子类
__construct()中必须显式调用parent::__construct(...),否则父类初始化逻辑不会执行
private 成员不会被继承,protected 是抽象类协作的关键
抽象类里的 private 属性或方法,子类完全不可见——不是“访问被拒”,而是根本不存在于子类作用域。所以别指望用 parent:: 调用父类 private 方法,也别试图在子类里重写它。
真正用于父子协作的是 protected 成员:它们既被子类继承,又不对外暴露,适合封装共享逻辑(比如统一的数据校验、状态初始化)。例如父类定义 protected function validate(): bool,子类可直接复用或重写。
- 子类重写
protected方法时,无需加abstract,也不影响父类抽象性 - 想让子类“必须提供某种能力”但又不规定实现细节?用
abstract protected function - 把本该
protected的成员误写成private,是抽象类设计中最隐蔽的协作断裂点
PHP 8.3 对只读属性和抽象类的组合支持有限
PHP 8.3 支持只读属性(readonly)在普通继承中的行为,但它**不支持**在抽象类中声明 abstract readonly 属性——这在语法上非法,会触发 Parse error。抽象属性是 PHP 8.4 才引入的特性。
如果你在抽象类里写了 public readonly string $name;,它就是个普通只读属性,子类能继承、能访问,但不能重新赋值;不过要注意:子类无法在自己的构造函数里给它赋值,必须通过 parent::__construct() 间接完成。
- 不要尝试在抽象类中用
abstract readonly—— 目前没这个语法 - 若需强制子类提供某个只读值,目前只能靠抽象方法(如
abstract public function getName(): string;)来替代 - PHP 8.3 的只读属性继承规则对抽象类完全适用:子类可继承、不可重声明、不可绕过构造函数赋值
protected 协作——这些决定一旦写进抽象类,就很难在不破坏子类的前提下调整。



















