Figure out how to avoid reference cycles for listener patterns, especially InventoryListener #6565
Labels
Category: Core
Related to internal functionality
Type: Cleanup
Removes or deprecates API methods or behaviour
Problem description
An inventory listener is strongly referenced by an inventory.
Since inventory listeners are typically used to dispatch updates to an owner (e.g. a delegate), this means that the listener needs to keep a ref to its owner.
However, in order to remove the listener once it's no longer needed, the owner must also keep a ref to the listener so it can be disposed of.
Since a listener keeping a hard ref to its owner would prevent the owner's
__destruct()
from being called (thereby requiring explicit disposal of dead owner objects), listeners therefore often have to use this kind of nasty weakref shit to avoid a reference cycle:PocketMine-MP/src/inventory/DelegateInventory.php
Lines 42 to 50 in 1481977
I've thought about this problem a few times, since it creates a lot of boilerplate code in places that would otherwise be simple.
This is not just a problem for
InventoryListener
. It appears in various other places too, like:ChunkListener
(has to be manually unregistered onPlayer
teardown)CraftingDataCache
(currently weakrefsCraftingManager
to avoid cycles)event\Listener
(has to be unregistered onPlugin
teardown, but tracks owner info - this only works because there is a registry of activePlugins
- there's no registry forChunkListener
,InventoryListener
etc)PermissibleInternal
<->PermissionAttachment
- currently gets around this by havingPermissibleInternal
encapsulated insidePermissibleBase
, which has no cycles - however this only works for as long as it's not necessary to dispatchPermissionAttachment
updates further up the reference chainPossible solutions
Alternative solutions that don't require API changes
The text was updated successfully, but these errors were encountered: