*/ private array $items = []; /** @var array */ private array $onAdd = []; /** @var array */ private array $onRemove = []; /** Register (or replace) a connection under $id. Fires onAdd listeners. */ public function add(string $id, object $connection): void { $this->items[$id] = $connection; foreach ($this->onAdd as $listener) { $listener($id, $connection); } } /** Remove a connection by id (no-op if absent). Fires onRemove listeners. */ public function remove(string $id): void { if (! isset($this->items[$id])) { return; } $connection = $this->items[$id]; unset($this->items[$id]); foreach ($this->onRemove as $listener) { $listener($id, $connection); } } public function has(string $id): bool { return isset($this->items[$id]); } public function get(string $id): ?object { return $this->items[$id] ?? null; } /** @return array */ public function all(): array { return $this->items; } /** @return array */ public function ids(): array { // Cast: PHP coerces numeric-string keys (e.g. "1") to int keys internally. return array_map(strval(...), array_keys($this->items)); } public function count(): int { return count($this->items); } /** * Apply a callback to every connection — the broadcast primitive. * The callback receives (object $connection, string $id). */ public function each(callable $callback): void { foreach ($this->items as $id => $connection) { $callback($connection, (string) $id); } } /** Listen for additions: function(string $id, object $connection): void. */ public function onAdd(callable $listener): void { $this->onAdd[] = $listener; } /** Listen for removals: function(string $id, object $connection): void. */ public function onRemove(callable $listener): void { $this->onRemove[] = $listener; } /** Remove every connection (firing onRemove for each). */ public function clear(): void { foreach (array_keys($this->items) as $id) { $this->remove((string) $id); // keys may be int (PHP numeric-string coercion) } } }