WeakMap 是专为对象生命周期绑定缓存设计的容器,键必须是对象且不增加引用计数,键销毁时条目自动清除;不支持非对象键、foreach 遍历和长期存储,适合元数据缓存。

WeakMap 不是用来替代普通数组或 SplObjectStorage 的通用容器,它是专为“对象生命周期绑定缓存”设计的——只要键对象被销毁,对应条目自动消失,不用手动清理。
WeakMap 的键必须是对象,且不增加引用计数
这是它和普通数组、SplObjectStorage 的本质区别。你不能用字符串、整数或 null 当键,否则会直接报错:TypeError: Invalid value used as weak map key。它只认对象实例本身(identity),不是 ID 或属性值。
- ✅ 正确写法:
$cache[$user] = $profile;($user是User实例) - ❌ 错误写法:
$cache['user-123'] = $profile;或$cache[123] = $profile; - ⚠️ 注意:
WeakMap不支持foreach遍历全部条目,因为键可能在任意时刻被回收;想检查是否存在,得用offsetExists($obj)
WeakMap 适合做元数据缓存,不适合做长期持久化存储
它的典型场景是:从某个对象派生出临时数据(比如用户权限、渲染上下文、ORM 查询结果),这些数据不该比对象活得更久。一旦 $user 被 unset 或超出作用域,WeakMap 里那条记录就自动没了。
- ✅ 推荐用法:类静态属性声明
private static WeakMap $metadata = new WeakMap();,所有实例共享同一张表 - ❌ 反模式:在方法里每次 new
WeakMap,等于白用——既没复用,也不弱(新实例没绑定任何对象生命周期) - ⚠️ 性能提示:
offsetGet()和offsetSet()是 O(1) 平均复杂度,但底层依赖哈希表,键对象频繁创建销毁时注意 GC 压力
WeakMap 无法解决值(value)端的循环引用
它只保证「键对象销毁 → 条目自动移除」,但不干预你塞进去的 $value 是否反过来强引用了键对象。如果 $value 是个闭包,且捕获了 $this,那就又套回去了。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 安全示例:
$cache[$user] = ['roles' => ['admin']];(纯数组,无反向引用) - ❌ 危险示例:
$cache[$user] = function() use ($user) { return $user->name; };(闭包强持$user,形成新闭环) - ⚠️ 检查手段:观察
__destruct()是否被调用;用gc_collect_cycles()强制触发一次回收后,再看count($cache)是否归零
WeakMap 的边界很清晰:它只管键的生死,不管值的世界。真正容易被忽略的是——你往里面塞的 value,可能悄悄把键又拽回来了。



















