>
> 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