抽象类可含具体方法、属性和构造函数,接口仅能声明public方法签名;php 8.0+ 接口支持默认参数但无函数体,且不可定义属性或非public方法。

abstract class 里能写具体方法,interface 不行
抽象类可以包含已实现的方法、属性,甚至构造函数;接口只能声明方法签名,所有方法默认是 public 且不能有方法体。PHP 8.0+ 虽支持接口中带默认值的参数,但依然不许写函数体。
常见错误现象:Fatal error: Interfaces may not include member variables —— 有人在 interface 里写了 $status = 'pending',直接报错。
- 抽象类适合“有共同行为基础”的场景,比如多个支付类都共享
logTransaction()实现 - 接口适合“能力契约”,比如
Payable、Refundable,不同类可随意组合实现 - 一个类只能
extends一个 abstract class,但能implements多个 interface
interface 方法默认 public,abstract class 方法可设 protected
interface 中所有方法自动是 public,你写 private function doX() 会直接语法报错;abstract class 里则可以明确用 protected 定义子类可用、外部不可调的钩子方法。
使用场景:比如框架中定义抽象控制器 BaseController,把 beforeAction() 设为 protected,让子类决定是否重写,但不允许外部调用。
立即学习“PHP免费学习笔记(深入)”;
- interface 的方法访问控制完全不可配置,删掉修饰符也不影响——它就是 public
- abstract class 中的
abstract方法也必须是public或protected,不能private - PHP 7.2+ 开始,interface 支持
static方法,但仍是public且必须有实现(即不是抽象的)
trait 和 interface 混用时,优先级和冲突规则
当一个类同时 use trait 并 implements interface,interface 只管“有没有这个方法”,不关心谁提供;而 trait 提供具体实现,可能和父类或另一个 trait 冲突。
容易踩的坑:Declaration of X::method() must be compatible with Y::method() —— 接口要求方法签名是 function foo(string $id),但你在 trait 里写了 function foo($id),类型不匹配就挂。
- interface 中的方法签名(含类型声明、返回类型、是否引用参数)会被严格校验,类实现时必须完全一致
- trait 中同名方法若与 interface 签名不符,PHP 会在实例化时报致命错误,不是运行时才暴露
- 多个 trait 引入同名方法?必须用
insteadof明确选一个,否则报Cannot inherit previously inherited or declared method
PHP 8.1+ 的 readonly class 对 abstract/interface 的影响
readonly 是类级别修饰符,只适用于具体类;abstract class 和 interface 都不能加 readonly 关键字,写了就语法错误。
性能影响几乎为零——readonly 是编译期约束,interface 和 abstract class 本身不参与实例化,自然不涉及字段可变性检查。
- 想约束子类字段只读?得靠抽象类中定义
protected readonly属性(PHP 8.2+),interface 依然无能为力 - interface 无法声明属性,所以
readonly、static、const之外的任何修饰都不适用 - 别试图在 interface 里写
public readonly string $id;——这连词法分析都过不去









