抽象类和接口不是“选哪个更好”,而是“解决哪类问题”:抽象类适用于共享实现、控制初始化、表达“is-a”关系及使用protected/private成员;接口适用于解耦组合无关类的行为能力、定义契约规范、支持多实现,且php 8.1+支持常量但不可替代抽象类的数据封装。

抽象类和接口不是“选哪个更好”,而是“解决哪类问题”。用错地方,后期改起来比重写还疼。
什么时候必须用 abstract class
当你需要共享代码实现、控制初始化流程,或明确表达“子类是父类的一种”时,abstract class 不可替代。
- 子类共用同一套构造逻辑?
__construct()只能在抽象类里定义,接口不能有构造方法 - 多个子类都要调用同一个日志记录逻辑?在抽象类里写
logToDatabase(),子类直接复用,不用重复实现 - 想强制子类按固定顺序执行某些步骤(模板方法模式)?用抽象类定义
execute()模板,调用before()、doWork()、after(),其中只有doWork()是抽象的 - 需要
protected或private方法封装内部细节?接口所有方法默认public,且不能声明私有成员
什么时候只能用 interface
当你要让完全无关的类具备同一行为能力,且不关心它们“是什么”,只关心“能做什么”时,interface 是唯一选择。
-
Bird和Drone毫无继承关系,但都该支持fly()—— 用Flyable接口 - 一个类既要可序列化、又要可缓存、还要可审计?PHP 单继承限制下,只能通过
implements Serializable, Cacheable, Auditable组合行为 - 框架约定回调契约(如 PSR 标准):你写的日志器必须实现
Psr\Log\LoggerInterface,否则容器拒绝注入 —— 这是解耦前提,不是代码复用需求 - PHP 8.1+ 允许接口定义常量(如
STATUS_PENDING = 'pending'),但仅限公共常量,仍不能替代抽象类的数据封装能力
abstract class 和 interface 能一起用吗
不仅能,而且常见。关键在于分清职责:抽象类管“骨架+部分血肉”,接口管“能力标签”。
- 一个
AbstractPaymentProcessor抽象类可以封装通用验签、异步通知处理逻辑,同时implements Refundable, Chargeable - 子类
AlipayProcessor继承它,并自动获得退款和支付能力的类型提示与契约约束 - 注意:抽象类
extends另一个类(或抽象类)时,只能有一个;但implements多个接口毫无压力 - 别在抽象类里塞一堆空方法假装是接口 —— 那是设计信号紊乱,IDE 提示会乱,类型系统也难推导
最容易被忽略的兼容性细节
PHP 对抽象类和接口的解析规则,在低版本和高版本间存在隐性差异,尤其影响升级。
- PHP 7.4 之前,接口方法参数不能带类型声明(如
log(string $msg));PHP 8.0+ 全面支持,但若项目需兼容旧环境,得降级写法 - 抽象类中
final public function是合法的,但接口里任何final都语法报错 —— 别试图在接口里“锁定实现” - 接口方法签名变更(比如加一个可选参数)属于**破坏性变更**:已实现该接口的类不会自动继承新签名,运行时报
Declaration must be compatible - 抽象类方法访问控制升级(如父类
protected,子类改成public)允许;但接口方法永远是public,子类实现时声明protected直接 fatal error
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











