📅 适用版本:PHP 8.4+
想象你去一家新开的披萨店。
你点了三份披萨:
- 芝士披萨(2分钟做好)
- 火腿披萨(3分钟做好)
- 海鲜披萨(10分钟做好,要洗虾、切鱼)
你朋友说:“我们现在只想吃芝士的,但怕一会儿饿,先把三份都点了吧。”
❌ 情况一:传统做法(浪费时间!)
服务员一听,立刻跑去厨房:
- 开始做海鲜披萨 🕐 10分钟
- 做火腿披萨 🕐 3分钟
- 做芝士披萨 🕐 2分钟
结果:你等了 15分钟 才吃到第一块披萨!
💡 这就像以前的 PHP 程序:
你一new
一个对象,它就立刻“开始做菜”,哪怕你暂时用不到它。
✅ 情况二:聪明做法(延迟做菜!)
新店有个聪明的办法:
服务员说:“我们已经接单了,但为了保证新鲜,现点现做。”
他给了你三张“披萨券”:
- “芝士披萨券”
- “火腿披萨券”
- “海鲜披萨券”
你现在拿着这三张券,但披萨还没做。
当你对服务员说:“我要吃芝士披萨!”
👉 服务员立刻去做,2分钟后端上来。
等你想吃海鲜披萨时,再说:“来份海鲜披萨!”
👉 这时才开始做,花10分钟。
✅ 你看:你立刻拿到了“披萨”(对象) ,但真正“做菜”(初始化)是等到你真要用时才开始的。
这就是 PHP 8.4 的「延迟对象」!
🧩 在代码里长什么样?
我们用 PHP 写一个“披萨服务”:
class SeafoodPizza {
public function __construct() {
sleep(10); // 模拟做披萨要10秒
echo "海鲜披萨做好了!\n";
}
public function eat() {
echo "真香!\n";
}
}
以前的做法(等10秒):
$pizza = new SeafoodPizza(); // ⏱️ 立刻开始 sleep(10)
echo "可以吃了"; // 要等10秒后才打印
现在的做法(延迟做):
$ref = new ReflectionClass(SeafoodPizza::class);
// 拿一张“披萨券”(延迟对象)
$pizza = $ref->newLazyGhost(function(SeafoodPizza $obj) {
new SeafoodPizza(); // 等你说“我要吃”时才执行这里
});
echo "可以吃了"; // ⏱️ 这里立刻打印!不用等10秒
// 5分钟后……
$pizza->eat(); // 👈 这时才开始 sleep(10),然后打印“真香”
✅ 输出顺序:
可以吃了
海鲜披萨做好了!
真香!
你看!你提前拿到了对象,但“做披萨”是延迟到你真要用时才开始的。
🎭 两种“披萨券”
PHP 提供了两种“延迟券”:
1. 幽灵券(Lazy Ghost)——“当场变身”
- 你拿着“券”。
- 你说“我要吃”,这张券当场变成真正的披萨。
- 之后你吃的、看的,都是它自己。
👉 用法:newLazyGhost()
✅ 优点:只有一个对象,省内存。
2. 代理券(Lazy Proxy)——“叫外卖”
- 你拿着“券”。
- 你说“我要吃”,服务员打电话让厨房做一份新的,然后端上来。
- 你吃的不是“券”变的,而是另一份真披萨。
👉 用法:newLazyProxy()
✅ 优点:可以控制谁来做(比如让“厨师长”做)。 ⚠️ 缺点:代理和真披萨是两个“身份证”(对象ID不同)。
🛑 什么时候会“触发做菜”?
只要你动了这个对象,就会触发:
- 读属性:
$pizza->name
- 写属性:
$pizza->price = 99
var_dump($pizza)
json_encode($pizza)
foreach
遍历clone $pizza
这些操作都会让“券”变成“真披萨”。
🚪 但有些操作不会触发(可以偷偷设置)
比如你知道披萨的“订单号”,想先记下来,但不想让他们开始做。
PHP 提供了“后门”:
// 先记下订单号,不触发做菜
$ref->getProperty('id')->setRawValueWithoutLazyInitialization($pizza, 123);
echo $pizza->id; // 这时不会触发初始化!因为 id 已知
👉 就像你说:“订单号是123,先记上,别开始做。”
📅 重要提醒
🔔 这个功能只有 PHP 8.4 及以上版本才有!
如果你用的是 PHP 8.3 或更早版本,是无法使用的。
✅ 一句话总结
延迟对象 = 先给“承诺券”,要用时再兑现
它让你的程序更快启动、更省资源,尤其适合那些“可能用,也可能不用”的重型对象。
🎉 比喻回顾
现实生活 | PHP 术语 |
---|---|
披萨订单 | new MyClass() |
披萨券 | 延迟对象(Lazy Object) |
说“我要吃” | 访问属性或方法 |
厨房开始做 | 对象初始化 |
幽灵券 | newLazyGhost() |
代理券 | newLazyProxy() |
现在,你应该明白了吧?😄
延迟对象不是“魔法”,而是一种聪明的懒加载策略——不该做的事,就先不做,等需要时再做。
就像聪明的餐厅:不让你等,也不让披萨凉。