Using PHP 8 WeakMap to Associate Data with Objects
PHP 8 introduced the WeakMap class, a powerful feature
that allows developers to associate arbitrary data with objects without
preventing those objects from being garbage collected. This article
provides a practical guide on how to use WeakMap to manage
object-linked data, prevent memory leaks, and write more efficient PHP
applications.
What is a WeakMap?
A WeakMap is a collection (map) where keys are objects,
and values can be any type of data. Unlike a standard array or
SplObjectStorage—which hold “strong” references to their
keys—a WeakMap holds “weak” references.
When an object used as a key in a WeakMap has no other
active references remaining in your application, PHP’s garbage collector
automatically destroys the object and removes its associated entry from
the WeakMap.
How to Use WeakMap
Using a WeakMap is straightforward as it implements the
ArrayAccess, Countable, and
IteratorAggregate interfaces. This means you can interact
with it just like a regular array.
Basic Implementation Example
Here is a simple example showing how to instantiate a
WeakMap, associate data with an object, and retrieve
it:
class User {
public function __construct(public string $username) {}
}
// 1. Initialize the WeakMap
$loginHistory = new WeakMap();
$user1 = new User('alice');
$user2 = new User('bob');
// 2. Associate data with the objects
$loginHistory[$user1] = ['last_login' => '2023-10-01', 'ip' => '192.168.1.1'];
$loginHistory[$user2] = ['last_login' => '2023-10-02', 'ip' => '192.168.1.2'];
// 3. Retrieve the associated data
echo $loginHistory[$user1]['last_login']; // Outputs: 2023-10-01Automatic Garbage Collection
The primary benefit of WeakMap is automatic cleanup. If
you unset or lose reference to the key object, the memory is freed
instantly.
// Check current count
echo count($loginHistory); // Outputs: 2
// Destroy one of the user objects
unset($user1);
// The associated entry in WeakMap is automatically removed
echo count($loginHistory); // Outputs: 1If you had used a standard array with object hashes
(spl_object_hash) or SplObjectStorage to store
this cache, user1 would remain in memory until the map
itself was destroyed, resulting in a memory leak.
Common Use Cases
1. Caching and Memoization
WeakMap is ideal for caching computed results derived
from objects (like database entities). If the entity is destroyed, the
cache is automatically cleared.
class InvoiceCalculator {
private WeakMap $cache;
public function __construct() {
$this->cache = new WeakMap();
}
public function calculateTotal(Invoice $invoice): float {
if (!isset($this->cache[$invoice])) {
// Simulate heavy calculation
$this->cache[$invoice] = $invoice->getSubTotal() * 1.21;
}
return $this->cache[$invoice];
}
}2. Attaching Metadata in Long-Running Processes
For daemon-like PHP environments (such as Swoole, RoadRunner, or
ReactPHP queue workers), keeping memory usage low is critical.
WeakMap allows you to attach temporary state, event
listeners, or metadata to request and connection objects without
worrying about manual teardown procedures.