本文目录导读:

在 PHP 中,构造函数(__construct())和析构函数(__destruct())的执行顺序有明确的规则,尤其是在继承和对象生命周期的上下文中。
单个类的基础顺序
对于单一类,顺序非常直接:
class MyClass {
public function __construct() {
echo "构造执行\n";
}
public function __destruct() {
echo "析构执行\n";
}
}
$obj = new MyClass();
echo "对象使用中\n";
unset($obj); // 或脚本结束
// 输出:
// 构造执行
// 对象使用中
// 析构执行
规则:构造 → 使用 → 析构
继承关系中的顺序(重点)
当存在继承时,PHP 不会自动调用父类的构造/析构方法,需要显式调用(通常通过 parent::)。
1 标准执行顺序
class ParentClass {
public function __construct() {
echo "父类构造\n";
}
public function __destruct() {
echo "父类析构\n";
}
}
class ChildClass extends ParentClass {
public function __construct() {
parent::__construct(); // 显式调用
echo "子类构造\n";
}
public function __destruct() {
echo "子类析构\n";
parent::__destruct(); // 显式调用
}
}
$obj = new ChildClass();
unset($obj);
// 输出:
// 父类构造
// 子类构造
// 子类析构
// 父类析构
构造顺序:父类 → 子类(类似叠箱子,从外到内构建基础)
析构顺序:子类 → 父类(与构造相反,后构建的先销毁)
不调用 parent:: 的情况
class ChildWithoutParentCall extends ParentClass {
public function __construct() {
echo "子类构造\n";
// 没有调用 parent::__construct()
}
}
$obj = new ChildWithoutParentCall();
// 输出:
// 子类构造 ← 父类构造不会自动执行
PHP 不会自动调用父类的构造/析构方法,必须显式调用。
多个对象 + 引用计数的析构顺序
当多个对象相互引用时,析构顺序取决于引用计数归零的时间:
class ObjA {
public function __destruct() {
echo "A 析构\n";
}
}
class ObjB {
public $a;
public function __destruct() {
echo "B 析构\n";
}
}
$a = new ObjA();
$b = new ObjB();
$b->a = $a; // A 的引用计数增加
unset($a); // 这里不会触发 A 的析构,因为 B 还引用它
unset($b); // 先析构 B,A 的引用计数归零,再析构 A
// 输出:
// B 析构
// A 析构
引用计数归零的先后顺序决定析构顺序。
静态属性与全局变量的析构顺序
class StaticExample {
public function __destruct() {
echo "Static 析构\n";
}
}
$globalObj = new StaticExample();
function test() {
$localObj = new StaticExample();
}
test(); // 局部变量在函数结束后析构
echo "脚本结束前\n";
// 输出:
// Static 析构 ← 局部变量
// 脚本结束前
// Static 析构 ← 全局变量(在脚本结束时析构)
规则:
- 局部变量:函数/方法结束时析构
- 全局变量:脚本结束时析构(顺序按变量定义顺序,但受引用影响)
- 静态变量:在全局变量之后析构
核心原则总结
| 场景 | 构造顺序 | 析构顺序 |
|---|---|---|
继承(显式调用 parent::) |
父类 → 子类 | 子类 → 父类(后进先出) |
继承(不调用 parent::) |
只执行子类构造 | 只执行子类析构 |
| 多个独立对象 | 按 new 顺序 | 按 unset/引用计数归零顺序 |
| 全局 vs 局部对象 | 局部优先于全局 |
最佳实践:
- 在子类构造中始终先调用
parent::__construct() - 在子类析构中始终先执行子类逻辑,再调用
parent::__destruct() - 避免在析构函数中抛出异常(PHP 8.0+ 会将其转为致命错误)
记忆口诀
构造像搭积木,从地基往上垒
析构像拆建筑,先拆顶层再拆底
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播