A registry keyed by object identity keeps every object it has ever seen alive, so a long-running worker grows in memory with the number of distinct objects it has processed.
final class MetadataCache
{
private array $byId = [];
private array $refs = [];
public function put(object $o, array $meta): void
{
$id = spl_object_id($o);
$this->byId[$id] = $meta;
$this->refs[$id] = WeakReference::create($o);
}
public function sweep(): void
{
foreach ($this->refs as $id => $ref) {
if ($ref->get() === null) {
unset($this->byId[$id], $this->refs[$id]);
}
}
}
}
WeakMap arrives in 8.0 and does all of this in one class, so the sweep and the two parallel arrays are a 7.4 workaround with a deadline. The detail that makes the sweep necessary rather than optional is that spl_object_id values are reused after collection, so a stale entry can be attributed to a completely different object — a bug that produces wrong data rather than a leak. SplObjectStorage is the obvious alternative and holds strong references, which is exactly the problem being solved.