PHP中接口必须用implements实现,不能用extends继承;抽象类只能用extends单继承。class A extends B implements C合法,但class A extends C(C为接口)会报Fatal error。

interface 必须用 implements,不能用 extends
PHP 中接口和抽象类的继承语法完全不互通。写 class A extends B implements C 是合法的,但 class A extends C(其中 C 是 interface)会直接报错:Fatal error: Class A cannot extend interface C。
常见错误是把接口当父类来继承,尤其在 IDE 自动补全或复制粘贴时手滑写错。一旦出现这个错误,PHP 解析器在编译阶段就拒绝继续,不会进入运行时。
- 接口只能用
implements,且可多个并列:class CacheManager implements CacheInterface, LoggerInterface - 抽象类只能用
extends,且仅能一个:class RedisCache extends AbstractCache - 如果既要继承又要实现,
extends必须写在implements前面,顺序反了会解析失败
abstract class 里构造函数必须显式调用 parent::__construct()
抽象类可以有构造函数,但它不是“默认自动触发”的。子类的 __construct() 不会隐式调用父类构造逻辑,哪怕父类只是初始化几个属性。
比如父类 AbstractUser 在构造函数里设置了 $this->createdAt = time(),子类 User 如果没写 parent::__construct(),这个时间戳就永远是 null 或未定义 —— PHP 不报错,但业务逻辑静默失效。
立即学习“PHP免费学习笔记(深入)”;
- 子类构造函数中必须手动加
parent::__construct(...),参数要匹配 - 如果父类构造函数有必填参数,子类不传就会触发
TypeError - 抽象类本身不能实例化,所以它的构造函数只对子类生效,这点和普通父类一致
interface 方法签名变更会导致所有实现类崩溃
接口方法一旦定义,就锁死了调用契约。给 CacheInterface::get(string $key): mixed 加个新参数 $ttl = null,所有已存在的实现类(如 FileCache、MemcachedCache)都会立刻报 Declaration must be compatible 错误。
这不是警告,是致命解析错误,部署后服务直接 500。PHP 8.0+ 的命名参数特性让这个问题更隐蔽:即使你没改参数数量,只改了参数名(比如从 $id 改成 $userId),调用方用命名参数时就会出错。
- 接口方法应尽量早定型,避免后期加参数;新增能力优先考虑新接口(如
CacheWithTtlInterface) - 不要在接口里用可变参数
...$args,它破坏签名稳定性 - IDE 无法帮你检查所有实现类是否同步更新,必须靠测试覆盖或静态分析工具(如 PHPStan)扫描
abstract method 必须以分号结尾,不能有花括号
这是最常被忽略的语法铁律。abstract public function save(): void { } 看起来像占位,但 PHP 直接报 Fatal error: Abstract function save() cannot contain body。
抽象方法本质是“声明契约”,不是“留空实现”。哪怕你只想 throw new Exception(),那也得等子类去写,抽象类里连空花括号都不允许。
- 正确写法只有两种:
abstract public function save(): void;或带类型声明的abstract public function load(int $id): array; - 访问控制符(
public/protected)不能省略,否则解析失败 -
private abstract是非法组合,PHP 解析器会直接拒绝 —— 私有方法根本不可能被子类实现



















