Mediator Pattern
debt(d7/e7/b7/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate phpstan as the tool but automated detection is explicitly marked 'no'. The code_pattern (N*M coupling mesh) is something phpstan can hint at structurally but won't flag as a mediator anti-pattern; recognising that the mediator has grown into a god class or that direct coupling should be mediated requires careful code review rather than automated tooling.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes introducing a mediator when many objects communicate directly — this means touching every participating component to redirect their communication through the mediator, updating interfaces, and restructuring interaction logic. This is inherently a cross-cutting change spanning multiple files and components rather than a single-file or small-component fix.
Closest to 'strong gravitational pull' (e7). The mediator applies_to web, cli, and queue-worker contexts and carries the decoupling tag for the whole system. Once introduced, every future feature that involves inter-component communication must be routed through or around it. The common_mistakes note about it becoming a god class confirms that it shapes how every change is made — components must coordinate via the mediator, imposing a persistent structural tax on all future work.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field directly names the trap: developers introduce the mediator to reduce coupling but inadvertently concentrate all coupling in the mediator, risking a god class. This is a well-documented gotcha that most developers who use the pattern encounter, but it is not catastrophic or entirely counterintuitive — the pattern does what it advertises at the component level, the trap emerges only over time with undisciplined growth.
Also Known As
TL;DR
Explanation
The Mediator pattern reduces chaotic many-to-many dependencies between objects by routing all communication through a central mediator. Instead of objects knowing about each other, they only know about the mediator. This reduces coupling from O(n²) to O(n). In PHP, the Command Bus (used in CQRS) is a form of mediator: commands are sent to the bus and routed to handlers, with no direct coupling between the sender and handler. Event dispatchers also act as mediators. Avoid letting the mediator become a God Object — it should route, not contain, business logic.
Common Misconception
Why It Matters
Common Mistakes
- The mediator becoming a god class that knows too much — distribute logic back to components and keep the mediator as a router.
- Using a mediator for components that have a simple, stable relationship — adds unnecessary complexity.
- Not distinguishing mediator (coordinates peers) from observer (notifies subscribers) — they solve different problems.
- Tightly coupling mediator to concrete component types — use interfaces so components can be swapped.
Code Examples
// Direct coupling between components — every component knows every other:
class Chat {
public function send(User $from, User $to, string $msg): void {
$to->receive($msg, $from); // Direct coupling — use a ChatMediator
}
}
// Without mediator: components know about each other
// With mediator: all communication goes through one hub
interface Mediator {
public function notify(object $sender, string $event): void;
}
class DialogMediator implements Mediator {
public function __construct(
private Checkbox $checkbox,
private Input $input,
private Button $submitBtn,
) {}
public function notify(object $sender, string $event): void {
if ($sender === $this->checkbox && $event === 'check') {
$this->input->setEnabled($this->checkbox->isChecked());
$this->submitBtn->setEnabled($this->checkbox->isChecked());
}
}
}