weakmap 是 php 8.0+ 引入的 final 类,必须用 new weakmap() 实例化,键必须为对象且自动随键销毁而清理,不支持非对象键、静态方法或函数调用。

WeakMap 不是函数,不能“调用”;它是 PHP 8.0 引入的原生类,必须实例化后通过 offsetSet、offsetGet 等方法操作。 直接写 WeakMap() 或 weakmap_init() 会报 Fatal error: Uncaught Error: Class "WeakMap" not found 或 Call to undefined function —— 因为它根本不是函数,也没有全局函数接口。
WeakMap 实例化必须用 new WeakMap()
WeakMap 是 final 类,不可继承,也不提供静态工厂方法。唯一合法创建方式就是 new WeakMap()。
- 错误写法:
WeakMap([])、WeakMap::create()、weak_map_new()—— 全部不存在 - 正确写法:
$map = new WeakMap(); - 注意:类名大小写敏感,
weakmap或weakMap都会失败 - PHP 8.0+ 才可用;低于 8.0 会直接 fatal,不会降级为警告或空对象
存取值必须用对象作键,且仅支持 ArrayAccess 语法
WeakMap 的键强制为对象(object),任何非对象类型(string、int、null)传入 offsetSet 或下标赋值时,会抛出 Fatal error: WeakMap key must be an object。
- 合法:
$map[$user] = ['role' => 'admin'];($user是new User()) - 非法:
$map['user_123'] = [...];、$map[123] = [...];、$map[null] = [...]; - 读取前建议先用
isset($map[$obj])或$map->offsetExists($obj)判断,避免 Notice(虽然$map[$obj]返回null而不报错) - 键对象被销毁后,对应项自动消失 —— 不会残留,也不触发回调
WeakMap 不支持 foreach 直接遍历键,需用 count() + Iterator
虽然 WeakMap 实现了 Traversable,但它的迭代器只遍历「当前仍存活的键值对」。若在 foreach 中修改 map(如 unset($map[$obj]))或键对象恰好在此期间被回收,行为不可靠。
- 安全遍历方式:
foreach ($map as $obj => $value) { ... }—— 这是推荐用法,底层已处理生命周期 - 不要手动调
$map->getIterator()再 while + next(),除非你明确需要控制迭代节奏 -
$map->count()返回的是当前存活条目数,不是初始插入数;它可能随 GC 发生而突变 - 没有
keys()或values()方法 —— 想提取所有键?只能遍历;想批量清理?只能逐个offsetUnset或重建新实例
WeakMap 和 WeakReference 的核心区别别搞混
两者都解决循环引用,但定位完全不同:WeakReference 是「单个弱指针」,WeakMap 是「按对象索引的弱缓存容器」。混用容易翻车。
- 用
WeakReference::create($obj)后,你得自己管理生命周期、判断get()是否返回null,适合打破双向依赖链(如 Observer 模式中 Subject 持有 WeakReference 到 Observer) - 用
WeakMap时,你根本不用管对象是否还活着 —— 它自动剔除死键;适合元数据绑定、对象级缓存(如$cache[$request] = $response) - 禁止把
WeakReference当键塞进WeakMap:键必须是原始对象,不是弱引用包装器 - WeakMap 键对象被回收时,不会调
__destruct来通知你 —— 它是静默的;需要通知机制?得自己加 Observer 或钩子
最易忽略的一点:WeakMap 的「弱」只作用于键,不限制值。如果你往里面存了一个大数组或闭包,而该闭包又捕获了其他长生命周期对象,内存照样涨。WeakMap 解决的是「键对象无法释放」的问题,不是万能内存保险丝。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











