PHP继承应基于“子类是否为父类的一种”及复用稳定行为契约,而非语法记忆;protected可被子类访问并覆盖,private不继承;final用于保护不可变行为,避免子类破坏契约。

PHP 继承不是靠背语法记住的,而是靠解决重复代码和明确类职责时自然用出来的。你写两个类都处理用户登录、校验、记录日志,这时才真正需要 extends;硬套继承反而会让代码更难改、更难测。
什么时候该用 extends 而不是复制粘贴?
判断标准很简单:子类是否「是」父类的一种,且复用的是「稳定不变的行为契约」,而不是临时拼凑的功能块。
- ✅ 适合:
User和AdminUser(AdminUser extends User),因为管理员「是」一种用户,核心属性($id、$email)和基础方法(login()、logout())可共用 - ❌ 不适合:
Order和Payment强行继承同一个基类,只因它们都有$createdAt—— 这属于数据字段重叠,不是类型关系,用组合或 trait 更干净 - ⚠️ 警惕:父类里塞了大量
if ($this instanceof XXX)分支逻辑 —— 这说明继承层级已失焦,该拆不该扩
protected 和 private 在继承中到底怎么影响访问?
别记口诀,看实际行为:子类能调用 protected 方法/属性,但不能碰 private —— 即使同名,也是两个独立变量。
class A {
protected $x = 'from A';
private $y = 'private in A';
public function show() {
echo $this->x . ' ' . $this->y; // ✅ 可访问
}
}
class B extends A {
protected $x = 'from B'; // ✅ 覆盖父类 protected 属性
private $y = 'private in B'; // ⚠️ 和父类 $y 完全无关
public function test() {
echo $this->x; // 输出 'from B'
// echo $this->y; // ❌ Notice: Undefined property: B::$y
}
}
常见坑:__construct() 里初始化 private 属性,结果子类完全感知不到,以为“继承没生效”——其实它根本没被继承。
立即学习“PHP免费学习笔记(深入)”;
为什么 final class 和 final public function 不是限制,而是保护?
当你明确某个类(如 DateTimeImmutable)或方法(如 JsonEncoder::encode())的行为必须严格一致,就不该允许子类随意覆盖。否则:
- 单元测试会失效:父类测过的逻辑,子类偷偷改掉,测试还绿着
- 类型提示失去意义:
function handle(User $u)接收AdminUser,但如果AdminUser::save()把数据库写到另一张表,调用方就崩了 - IDE 和静态分析工具(如 PHPStan)无法准确推导行为,补全和报错变弱
真实建议:新项目中,所有不打算被继承的类,第一行就加 final class;核心业务方法(比如计算折扣、生成 token)也优先 final,除非你真想开放定制点。
继承最难的部分,从来不是语法,而是判断「这个抽象是否足够稳定」——一旦父类接口要动,所有子类都得跟着动。很多人卡在这一步,不是不会写 extends,而是不敢确定「这里到底该不该继承」。



















