PHP Mediator Pattern
A short screencast: the Mediator pattern — objects communicate through a mediator instead of talking to each other directly. We build a chat room where one message reaches every participant.
Overview
The Mediator removes direct links between objects and replaces them with communication through a single central object. A User knows only the Mediator, never the other participants: its send() method simply calls notify() on the mediator. The mediator itself, ChatRoom, keeps the list of participants and delivers a message to everyone except the sender. Adding a new participant or changing the delivery rule can be done without touching the User class — all interaction logic is gathered in one place.
UML diagram
Code
Mediator.php
interface Mediator
{
public function notify(User $sender, string $message): array;
}
User.php
class User
{
public function __construct(private Mediator $mediator, public readonly string $name) {}
public function send(string $message): array
{
return $this->mediator->notify($this, $message);
}
public function receive(string $message): string
{
return $this->name.' received: '.$message;
}
}
ChatRoom.php
class ChatRoom implements Mediator
{
private array $users = [];
public function addUser(User $user): void
{
$this->users[] = $user;
}
public function notify(User $sender, string $message): array
{
$log = [];
foreach ($this->users as $user) {
if ($user !== $sender) {
$log[] = $user->receive($message);
}
}
return $log;
}
}
demo.php
require_once 'Mediator.php';
require_once 'User.php';
require_once 'ChatRoom.php';
$chat = new ChatRoom;
$alice = new User($chat, 'Alice');
$bob = new User($chat, 'Bob');
$carol = new User($chat, 'Carol');
$chat->addUser($alice);
$chat->addUser($bob);
$chat->addUser($carol);
foreach ($alice->send('Hello, team!') as $line) {
echo $line.PHP_EOL;
}
Example output
After php demo.php Alice's message reaches the others, even though she does not know them directly:
Bob received: Hello, team!
Carol received: Hello, team!
Advantages
- Participants are decoupled: each knows only the mediator, not every other participant.
- The interaction logic is gathered in one class instead of being spread across participants.
- New participants and communication rules can be added without touching existing ones.
- The number of links drops from many-to-many to each-to-mediator.
When to use
- When objects have many tangled links that are hard to follow.
- When objects should not need to know about each other directly.
- When the interaction behaviour must be reused independently of the objects.
- When the communication logic changes more often than the participants themselves.
Usage in Laravel
In Laravel the mediator role is most often played by the event bus: Illuminate\Events\Dispatcher broadcasts an event to its listeners so that the sender knows nothing about the receivers — it only calls event() or dispatch(). The same principle applies to the notification manager Illuminate\Notifications\ChannelManager and to the service container Illuminate\Container\Container, which binds classes by contract so they never have to reference each other directly.