This is an old revision of the document!
PHP RFC: Weak maps
- Date: 2019-11-04
- Author: Nikita Popov nikic@php.net
- Proposed Version: PHP 8.0
- Status: Under Discussion
- Implementation: https://github.com/php/php-src/pull/4882
Introduction
Weak maps allow creating a map from objects to arbitrary values (similar to SplObjectStorage) without preventing the objects that are used as keys from being garbage collected. If an object key is garbage collected, it will simply be removed from the map.
In PHP 7.4 first-class support for weak references was already introduced. However, raw weak references are only of limited usefulness by themselves and weak maps are much more commonly used in practice. It is not possible to implement an efficient weak map on top of PHP weak references, because the ability to register a destruction callback is not provided.
The general use case for weak maps is to associate data with individual object instances, without forcing them to stay alive and thus effectively leak memory in long-running processes. For example, a weak map may be used to memoize a computation result:
class FooBar { private WeakMap $cache; public function getSomethingWithCaching(object $obj) { return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj); } // ... }
This will invoke the computeSomethingExpensive()
method only once for each object. At the same time it will also drop the cached value from the map if the object is destroyed. Doing the same with a normal array (or rather SplObjectStorage
) would result in a memory leak.
Proposal
Add a WeakMap
class with the following prototype:
final class WeakMap implements ArrayAccess, Countable, Traversable { public function offsetGet($object); public function offsetSet($object, $value): void; public function offsetExists($object): bool; public function offsetUnset($object): void; public function count(): int; }
Objects used as weak map keys are “weakly referenced”, which means that they are not prevented from being garbage collected. If an object that is used as a weak map key is garbage collected, the key is removed from the weak map. This is illustated in the following example:
$map = new WeakMap; $obj = new stdClass; $map[$obj] = 42; var_dump($map); // object(WeakMap)#1 (1) { // [0]=> // array(2) { // ["key"]=> // object(stdClass)#2 (0) { // } // ["value"]=> // int(42) // } // } // The object is destroyed here, and the key is automatically removed from the weak map. unset($obj); var_dump($map); // object(WeakMap)#1 (0) { // }
Some details of the WeakMap
behavior are outlined in the following:
- Just like
WeakReference
,WeakMap
is not serializable and setting dynamic properties on it is forbidden. - Unlike
WeakReference
,WeakMap
can be cloned. CloningWeakReference
s is not allowed because the objects are uniqued, which does not apply toWeakMap
s. - Using a non-object key in
$map[$key]
or one of theoffset*()
methods results in aTypeError
exception. - Appending to a weak map using
$map[]
results in anError
exception. - Reading a non-existent key results in an
Error
exception. - Overloaded operations on map entries are supported, i.e.
$map[$obj][] = $x
and similar work. - By-reference iteration of
WeakMap
s is supported.
Backward Incompatible Changes
No backwards incompatible changes apart from using the WeakMap
class name.
Vote
Add WeakMap class in PHP 8.0? Yes/No.