WeakMap for a cache that must not keep objects alive

A per-request memoisation cache keyed by object was holding every entity loaded during a long-running command, and the command was using 900 MB by the end.

// the leak: SplObjectStorage keeps a strong reference
private SplObjectStorage $computed;

public function totalFor(Order $order): Money
{
    return $this->computed[$order] ??= $this->compute($order);
}

// WeakMap: the entry disappears when the order does
private WeakMap $computed;   // 8.0+

// 40,000 orders, one at a time:
//   SplObjectStorage   912 MB, growing
//   WeakMap             41 MB, flat

This only helps when the cache is genuinely subordinate to the object’s lifetime, which is the case for a derived value and not for a lookup table. The trap is that anything else holding a reference — an identity map, a collection the caller kept — keeps the entry alive too, so the memory graph looks identical until the last reference goes. Measuring before and after is the only way to know it did anything.