WeakMap

WeakMap, WeakReference and Caching Without Leaks

A cache that stores objects in an array keeps every one alive, because the array holds a reference. In a request that is a slow leak; in a worker that runs for hours (FrankenPHP and Worker Mode) it ends in a crash. A WeakMap (PHP 8.0) uses objects as keys without counting as a reference, and an entry vanishes when its key object is destroyed. A WeakReference (PHP 7.4) holds one object the same way, and its get() returns null once the object is gone.

weak.php: a per-object cache that empties itselfPHP
<?php
final class Product { public function __construct(public readonly int $id) {} }
final class PriceCache
{
    public WeakMap $prices;
    public function __construct() { $this->prices = new WeakMap(); }
    public function price(Product $p): float { return $this->prices[$p] ??= $p->id * 1.5; }
}
$cache = new PriceCache();
$products = array_map(fn(int $i): Product => new Product($i), range(1, 50_000));
array_walk($products, fn(Product $p) => $cache->price($p));
printf("%6d cached, %.1f MB\n", count($cache->prices), memory_get_usage() / 2 ** 20);
$products = [];                                          // the page is done with them
printf("%6d cached, %.1f MB\n", count($cache->prices), memory_get_usage() / 2 ** 20);
Output
 50000 cached, 11.1 MB
     0 cached, 5.9 MB

Use a WeakMap to attach computed data to objects you do not own: a price per product, metadata per entity. Data keyed by an ID or a string still belongs in a size-capped array or in APCu or Redis 2,763 (APCu, Redis, Memcached).