>
> The answer is: it depends. If you don’t need the array to clean up after
> itself, you can indeed use an array of WeakReference to get most of the way
> there. If you want it to clean up after an object gets removed, you either
> need to add support to the stored object’s destructor (which isn’t always
> possible for built-in or final types), or create your own garbage collector
> that scans the array.
>

It is indeed doable in userland using WeakReferences, with a small
performance penalty:

```
class ReverseWeakMap implements Countable, IteratorAggregate, ArrayAccess
{
    /**
     * @var array<int|string, WeakReference>
     */
    private array $map = [];

    public function count(): int
    {
        foreach ($this->map as $value => $weakReference) {
            if ($weakReference->get() === null) {
                unset($this->map[$value]);
            }
        }

        return count($this->map);
    }

    public function getIterator(): Generator
    {
        foreach ($this->map as $value => $weakReference) {
            $object = $weakReference->get();

            if ($object === null) {
                unset($this->map[$value]);
            } else {
                yield $value => $object;
            }
        }
    }

    public function offsetExists(mixed $offset)
    {
        if (isset($this->map[$offset])) {
            $object = $this->map[$offset]->get();

            if ($object !== null) {
                return true;
            }

            unset($this->map[$offset]);
        }

        return false;
    }

    public function offsetGet(mixed $offset): object
    {
        if (isset($this->map[$offset])) {
            $object = $this->map[$offset]->get();

            if ($object !== null) {
                return $object;
            }

            unset($this->map[$offset]);
        }

        throw new Exception('Undefined offset');
    }

    public function offsetSet(mixed $offset, mixed $value): void
    {
        $this->map[$offset] = WeakReference::create($value);
    }

    public function offsetUnset(mixed $offset): void
    {
        unset($this->map[$offset]);
    }
}
```

Now that I think about it, it might be simpler to add an “onRemove()”
> method that takes a callback for the WeakReference class.
>
> — Rob
>


A callback when an object goes out of scope would be a great addition to
both WeakReference & WeakMap indeed, it would allow custom userland weak
maps like the above, with next to no performance penalty!

- Benjamin

Reply via email to