PHP Conference Japan 2024

WeakMap 类

(PHP 8)

介绍

一个WeakMap 是一个映射(或字典),它接受对象作为键。但是,与类似的SplObjectStorage不同,WeakMap 的键中的对象不会增加对象的引用计数。也就是说,如果在任何时候对象唯一的剩余引用是 WeakMap 的键,则该对象将被垃圾收集并从 WeakMap 中移除。它的主要用例是构建从对象派生的数据的缓存,这些缓存不需要比对象存活更长时间。

WeakMap 实现 ArrayAccessTraversable(通过 IteratorAggregate)和 Countable,因此在大多数情况下,它可以用与关联数组相同的方式使用。

类概要

final class WeakMap implements ArrayAccess, Countable, IteratorAggregate {
/* 方法 */
public count(): int
public offsetExists(object $object): bool
public offsetGet(object $object): mixed
public offsetSet(object $object, mixed $value): void
public offsetUnset(object $object): void
}

示例

示例 #1 Weakmap 使用示例

<?php
$wm
= new WeakMap();

$o = new stdClass;

class
A {
public function
__destruct() {
echo
"Dead!\n";
}
}

$wm[$o] = new A;

var_dump(count($wm));
echo
"Unsetting...\n";
unset(
$o);
echo
"Done\n";
var_dump(count($wm));

以上示例将输出

int(1)
Unsetting...
Dead!
Done
int(0)

目录

添加注释

用户贡献的注释 2 条注释

Samu
1 年前
PHP 的 WeakMap 实现允许迭代 WeakMap 的内容,因此了解它有时为什么很危险并需要仔细考虑非常重要。

如果 WeakMap 的对象由其他服务(例如 Doctrine 的 EntityManager)“管理”,则永远不能假设如果对象仍然存在于 WeakMap 中,它仍然由 Doctrine 管理,因此可以安全地使用。

Doctrine 可能已经丢弃了该实体,但某些不相关的代码可能仍然持有对它的引用,因此它也仍然存在于映射中。

如果您将托管对象放入 WeakMap 并稍后迭代 WeakMap(例如在 Doctrine flush 之后),则对于每个此类对象,您必须验证它在对象来源的上下文中是否仍然有效。

例如,将分离的 Doctrine 实体分配给另一个实体的属性将导致关于在层次结构中发现未持久化/未管理的实体的错误。
Anton
8 个月前
请记住,如果 Enum case 被用作 WeakMap 的键,它将永远不会被移除,因为它内部总会有一个对它的引用(不确定为什么,可能是因为枚举基本上是一个常量)。
因此,以下两个 WeakMap 将始终具有键 Enum::Case。但是,您仍然可以手动取消设置它

$weakMap = new WeakMap();
$object = Enum::Case;

$weakMap[$object] = 123;
unset($object);
var_dump($weakMap->count()); // 1

///

$weakMap = new WeakMap();
$weakMap[Enum::Case] = 123;
var_dump($weakMap->count()); // 1

///

$weakMap = new WeakMap();
$weakMap[Enum::Case] = 123;
unset($weakMap[Enum::Case]);
var_dump($weakMap->count()); // 0
To Top