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 個月前
請記住,如果將列舉類型案例作為鍵放入 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