当前位置: 首页 > news >正文

PHP 继承与静态机制深度解析

📘 PHP 继承与静态机制深度解析

—— 从 extendsstatic 的完整知识体系(适合深度复习)

本文涵盖 PHP 7.4 ~ PHP 8.4 的继承规则、可见性、后期静态绑定、只读属性、内部类兼容性等核心机制,结合设计原则与实际案例,助你构建完整的 OOP 认知框架。


一、继承的本质:代码复用与契约承诺

✅ 什么是继承?

使用 extends 关键字,子类可以继承父类的 public 和 protected 成员(方法、属性、常量),实现功能复用。

class Animal {public function breathe() { echo "呼吸空气\n"; }
}
class Dog extends Animal {public function bark() { echo "汪汪叫\n"; }
}
(new Dog())->breathe(); // ✅ 继承自 Animal

🔑 继承不是“复制粘贴”,而是一种 “is-a”关系Dog is an Animal


二、继承了什么?哪些不能继承?

成员类型是否继承说明
public 成员✅ 是外部可访问
protected 成员✅ 是子类内部可访问
private 成员❌ 否仅父类内部可用,但可通过 parent:: 间接调用

🧠 重要补充:private 成员的“类级封装”

同一个类的不同实例,可以互访 private 成员!

class BankAccount {private $balance = 0;public function transfer(BankAccount $other, $amount) {$this->balance -= $amount;$other->balance += $amount; // ✅ 合法!类内部可访问同类实例的 private 属性}
}$a = new BankAccount();
$b = new BankAccount();
$b->transfer($a,1000);

✅ 原因:private类级别的封装,不是实例级别的。


三、可见性规则:只能“放宽”,不能“收紧”

✅ 正确:放宽可见性(允许)

class Parent {protected function foo() {}
}
class Child extends Parent {public function foo() {} // ✅ OK:protected → public
}

❌ 错误:收紧可见性(违反 LSP)

class Parent {public function bar() {}
}
class Child extends Parent {protected function bar() {} // ❌ Fatal Error!
}

🔥 原因:违反 里氏替换原则(LSP)
“子类对象应能替换父类对象而不破坏程序行为。”
如果 Childbar() 变成 protected,外部代码调用时会失败。


✅ 特例:构造方法可以“收紧”可见性!

这是 PHP 中唯一的例外

class Singleton {public function __construct() {} // 父类 public
}
class Restricted extends Singleton {private function __construct() {} // ✅ 允许!用于单例模式
}

💡 用途:实现单例、工厂模式,控制对象创建。


四、只读属性(readonly)的继承规则

❌ 不允许互相覆盖

class A {public int $prop = 1;
}
class B extends A {public readonly int $prop = 2; // ❌ Fatal Error!
}
class C {public readonly int $prop = 1;
}
class D extends C {public int $prop = 2; // ❌ Fatal Error!
}

✅ 正确做法

  • 子类可显式声明同名 readonly 属性,也就是继承,只是把代码又写一了一遍:

    class E extends C {public readonly int $prop; // ✅ 允许
    }
    
  • 子类可在构造函数中为 readonly 属性赋值。

🔑 原因:readonly 是一种“不可变”契约,不能被破坏。


五、方法重写:签名必须兼容(PHP 8.0+ 更严格)

PHP 8.0 开始,方法重写必须满足:

  1. 参数兼容(支持协变/逆变)
  2. 返回类型兼容
  3. 可见性不能收紧
  4. 不能删除返回类型声明

否则会触发 Fatal Error(PHP 7.x 是警告)。


六、继承内部类:返回类型兼容性(PHP 8.1+)

📌 背景

PHP 8.1 为大多数内部方法“暂定添加返回类型”,你必须遵守:

class MyData implements JsonSerializable {public function jsonSerialize(): mixed { // ✅ 必须写 : mixedreturn ['name' => 'Alice'];}
}

❌ 如果不写:

public function jsonSerialize() { ... }

⚠️ 触发弃用通知:

深色版本
Deprecated: Return type should be compatible with ...

✅ 解决方案:#[ReturnTypeWillChange]

用于兼容 PHP < 8.1 的库开发:

use ReturnTypeWillChange;class MyData implements JsonSerializable {#[ReturnTypeWillChange]public function jsonSerialize() {return ['name' => 'Alice'];}
}

⚠️ 注意:这是临时方案,长期应加上正确返回类型。


七、:: 操作符:静态世界的“遥控器”

:: 的完整用法

用法示例说明
静态属性ClassName::$prop必须带 $
静态方法ClassName::method()常见调用方式
常量ClassName::CONSTANT不带 $
父类调用parent::method()在子类中调用父类方法
自身类self::method()指向定义它的类
实际调用者static::method()后期静态绑定(重点!)

八、self vs static:早期绑定 vs 后期静态绑定

🔍 核心区别

关键字绑定时机含义特点
self编译时(早期绑定)“写这个方法的类”死板,不随调用者变
static运行时(后期绑定)“实际调用这个方法的类”灵活,智能识别上下文

🍕 生活化比喻:总公司与分公司

class 总公司 {protected static $logo = '蓝色地球';public static function 显示Logo_A() {echo self::$logo . "\n";   // ❌ 固定用总公司的}public static function 显示Logo_B() {echo static::$logo . "\n"; // ✅ 谁调用,就用谁的}
}class 北京分公司 extends 总公司 {protected static $logo = '北京天坛';
}北京分公司::显示Logo_A(); // 输出:蓝色地球 ❌
北京分公司::显示Logo_B(); // 输出:北京天坛 ✅

static 实现了“一套制度,多地执行”。


九、后期静态绑定(Late Static Binding)的应用场景

✅ 场景 1:通用模型 + 不同配置

class Model {protected static $table;public static function find($id) {return "SELECT * FROM " . static::$table . " WHERE id = $id";}
}class User extends Model { protected static $table = 'users'; }
class Post extends Model { protected static $table = 'posts'; }User::find(1);  // ✅ SELECT * FROM users ...
Post::find(2);  // ✅ SELECT * FROM posts ...

✅ 场景 2:静态工厂模式

class Animal {public static function create() {return new static(); // 返回调用者的实例}
}class Dog extends Animal {}
class Cat extends Animal {}$dog = Dog::create(); // ✅ 返回 Dog 实例
$cat = Cat::create(); // ✅ 返回 Cat 实例

new static() 是关键!


十、最佳实践与陷阱总结

建议说明
✅ 优先使用 static 而不是 self在静态方法中,尤其是父类方法
✅ 静态属性用 protectedprivate避免外部随意修改
✅ 文档说明静态方法行为特别是涉及后期绑定时
❌ 避免在非静态方法中滥用 static::容易混淆,优先用 $this->
✅ 使用 final class 防止继承当你不希望类被扩展时

✅ 总结图谱

text
深色版本
PHP 继承与静态机制全景图
│
├── 继承:extends
│   ├── public / protected 成员可继承
│   ├── private 成员不继承(但同类实例可互访)
│   ├── 可见性只能放宽(LSP 原则)
│   └── 构造方法是唯一可收紧的例外
│
├── 只读属性:readonly
│   ├── 不能与普通属性互相覆盖
│   └── 子类可显式声明 readonly
│
├── 方法重写
│   ├── PHP 8.0+ 严格签名兼容
│   └── PHP 8.1+ 内部类返回类型必须匹配
│       └── 可用 #[ReturnTypeWillChange] 兼容旧版本
│
└── 静态机制├── :: 操作符:访问静态成员├── self:早期绑定(定义类)└── static:后期静态绑定(调用类)└── 实现“一套逻辑,多种配置”

📚 一句话口诀(终极复习)

extends 是父子关系,:: 是遥控器,
self 是亲爹,static 是干爹;
谁调用,static 就跟谁走!”

http://www.dtcms.com/a/318511.html

相关文章:

  • 防御保护综合练习
  • 北斗变形监测技术应用解析
  • HTTP Flood攻击:数字时代的“蝗虫灾害“与智能防护之道
  • AI推理新高度:Claude Opus 4.1如何解决复杂逻辑问题
  • SELinux 安全机制详解与管理
  • AI_提示词Prompt
  • 大模型后训练——Online-RL基础
  • Godot ------ 自定义布局以及自定义引擎风格
  • 8.6日作业
  • 五、Envoy集群管理
  • Redis Redis 常见数据类型
  • TFTP: Linux 系统安装 TFTP,文件系统启动后TFTP使用
  • Java 启动命令的完整解析
  • 【渲染流水线】[应用阶段]-[裁剪]以UnityURP为例
  • GeoTools 结合 OpenLayers 实现缓冲区分析
  • LINQ 要点
  • 92、【OS】【Nuttx】【构建】cmake 支持构建的目标
  • SOD-YOLO:增强基于YOLO的无人机影像小目标检测
  • Product Hunt 每日热榜 | 2025-08-06
  • GoogLeNet训练
  • FastDeploy2.0:Error reading file: SafeTensorError::MetadataIncompleteBuffer
  • chdir系统调用及示例
  • 【C/C++】形参、实参相关内容整理
  • 零基础-动手学深度学习-8.7. 通过时间反向传播
  • Spring_事务
  • 国产3D大型装配设计新突破①:图纸打开设计双加速 | 中望3D 2026
  • C语言的数组与字符串练习题2
  • 如何快速翻译PPT中的文字(或简繁体转换)
  • 【51单片机2个独立按键2个独立数码管静态显示内容自定】2022-10-22
  • Perforce P4 Plan - DevOps实时规划工具