The goal is not to use the fanciest one. The goal is to choose the one that matches the dependency you actually have.
Use a Direct Method Call When the Relationship Is Explicit
Use a direct call when:
- one sender knows one receiver
- the dependency is deliberate and stable
- the sender already has the receiver reference
- you want the smallest amount of ceremony
Example:
$doorIndicator->flashIndicator();
This is often the clearest choice when one object is deliberately coordinating another.
Use Signal When the Owner Is Known
Use Signal when:
- the owner instance is already known
- that owner wants to expose a callback surface
- several listeners may attach to that one owner
- subscriptions are part of the design
Think:
- one specific
Door - one specific
Weapon - one specific
AnimationController
Use EventBus When the Reaction Should Be Decoupled
Use EventBus when:
- listeners should not know the dispatcher ahead of time
- several unrelated systems may react
- you care that an event happened, not that you already hold the sender reference
- the event name and payload describe the gameplay moment
Think:
- player died
- checkpoint reached
- score changed
- round started
A Fast Rule of Thumb
If you already have the reference and only one collaborator needs to react, start with a direct method call.
If one known owner wants to expose a reusable callback surface, use Signal.
If the event should travel across systems without shared references, use EventBus.
A Practical Test
Ask:
"Would this still make sense if several unrelated systems wanted to react?"
If the answer is yes, that usually points to EventBus.
Ask:
"Do subscribers still need a reference to one exact owner instance?"
If the answer is yes, that usually points to Signal.
Ask:
"Do I already know exactly who needs to respond?"
If the answer is yes, that usually points to a direct call.