SplObjectStorage as a set, before WeakMap existed

SplObjectStorage is a set of objects with O(1) membership, and it holds a strong reference to everything in it.

$seen = new SplObjectStorage();

foreach ($nodes as $node) {
    if ($seen->contains($node)) {
        continue;
    }

    $seen->attach($node, $metadata);   // it is also a map
}

// count($seen), $seen[$node], foreach — all work.
// and nothing in it will ever be garbage collected
// while the storage lives.

It is genuinely the right tool for cycle detection in a graph walk, where the lifetime is one function call and the strong reference is irrelevant. Using it as a long-lived cache is the mistake, and it was the only option before WeakMap. The dual nature — a set when attached with one argument and a map with two — makes reading code that uses it harder than it should be, and naming the variable after which one it is helps more than it sounds.