Behavioral Patterns: Strategy, Observer, Command
Model behavior and communication with behavioral patterns.
Behavioral Patterns: Strategy, Observer, Command is a free PHP Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the PHP Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Modeling behavior
Behavioral patterns govern how objects collaborate and distribute responsibility. We focus on three that appear constantly in real PHP systems:
- Strategy — swap an algorithm at runtime.
- Observer — broadcast events to interested listeners.
- Command — turn a request into an object you can queue, log or undo.
Strategy: the idea
The Strategy pattern defines a family of interchangeable algorithms behind one interface and lets the client choose at runtime. It replaces the sprawling switch below with polymorphism: the context delegates to whichever strategy it holds.
<?php
// The smell Strategy removes: branching on a type code
function price(string $type, float $base): float {
switch ($type) {
case 'standard': return $base + 5;
case 'express': return $base + 15;
default: throw new InvalidArgumentException($type);
}
}
echo price('express', 10), PHP_EOL; // 25
Strategy in code
Here a shipping cost depends on the chosen carrier. Each strategy encapsulates one pricing algorithm; the context stays unchanged when you add a carrier.
<?php
interface ShippingStrategy { public function cost(float $weight): float; }
final class Standard implements ShippingStrategy {
public function cost(float $w): float { return 5 + $w * 0.5; }
}
final class Express implements ShippingStrategy {
public function cost(float $w): float { return 15 + $w * 1.2; }
}
final class Cart {
public function __construct(private ShippingStrategy $strategy) {}
public function setStrategy(ShippingStrategy $s): void { $this->strategy = $s; }
public function quote(float $weight): float { return $this->strategy->cost($weight); }
}
$cart = new Cart(new Standard());
echo $cart->quote(10), PHP_EOL; // 10
$cart->setStrategy(new Express());
echo $cart->quote(10), PHP_EOL; // 27
Strategy with closures
In PHP a strategy doesn't always need a class. For lightweight cases a callable or first-class callable syntax is a perfectly valid strategy. Use full classes when the algorithm has its own state or dependencies; use closures for simple, stateless choices.
<?php
$strategies = [
'asc' => fn(array $a) => sort($a) ? $a : $a,
'desc' => fn(array $a) => rsort($a) ? $a : $a,
];
$data = [3, 1, 2];
print_r($strategies['desc']($data)); // [3,2,1]
Observer: the idea
The Observer pattern lets a subject notify many observers when its state changes, without knowing who they are. This decouples the source of an event from its handlers and underpins event systems, hooks and reactive updates.
Observer in code
The subject keeps a list of observers and calls update() on each. New listeners attach without changing the subject's logic.
<?php
interface Observer { public function update(string $event): void; }
final class OrderSubject {
private array $observers = [];
public function subscribe(Observer $o): void { $this->observers[] = $o; }
public function placed(string $id): void {
foreach ($this->observers as $o) { $o->update("order $id placed"); }
}
}
final class EmailObserver implements Observer {
public function update(string $e): void { echo "email: $e" . PHP_EOL; }
}
final class AuditObserver implements Observer {
public function update(string $e): void { echo "audit: $e" . PHP_EOL; }
}
$subject = new OrderSubject();
$subject->subscribe(new EmailObserver());
$subject->subscribe(new AuditObserver());
$subject->placed('42');
Observer vs PSR-14
Modern PHP often expresses Observer through PSR-14 event dispatchers: a dispatcher routes an event object to registered listeners. The mental model is the same (subject = event, observers = listeners) but a dispatcher decouples them further and supports stoppable events. SplObserver/SplSubject exist in the SPL but are rarely used today.
Command: the idea
The Command pattern encapsulates a request as an object: the action, its receiver and its parameters. Because the request is now data, you can queue it, log it, retry it, or undo it. The simplest command just reifies an intent as a value, as shown below.
<?php
final class SendEmail {
public function __construct(
public readonly string $to,
public readonly string $subject
) {}
}
// The request is now data you can store, serialize, or enqueue
$cmd = new SendEmail('user@example.com', 'Welcome');
echo json_encode($cmd), PHP_EOL;
Command in code
Each command implements execute(). An invoker holds and runs them, decoupled from what they do. Adding undo() turns this into a full undo stack.
<?php
interface Command { public function execute(): string; }
final class Light { public bool $on = false; }
final class TurnOn implements Command {
public function __construct(private Light $light) {}
public function execute(): string { $this->light->on = true; return 'light on'; }
}
final class TurnOff implements Command {
public function __construct(private Light $light) {}
public function execute(): string { $this->light->on = false; return 'light off'; }
}
final class Invoker {
private array $queue = [];
public function add(Command $c): void { $this->queue[] = $c; }
public function run(): void {
foreach ($this->queue as $c) { echo $c->execute(), PHP_EOL; }
}
}
$light = new Light();
$inv = new Invoker();
$inv->add(new TurnOn($light));
$inv->add(new TurnOff($light));
$inv->run();
Command buses
Frameworks build a command bus on this pattern: a command DTO is dispatched to exactly one handler. Middleware around the bus can add transactions, validation and logging uniformly. Because commands are plain serializable objects, the same handler can run synchronously or be pushed onto a queue worker.
Choosing among them
- Strategy: one operation, many interchangeable algorithms, chosen by the caller.
- Observer: one event, many independent reactions, source doesn't know the handlers.
- Command: reify a request so it can be queued, logged, retried or undone.
They combine well: a command handler may pick a strategy and emit observer events.
Quick Check
Match the requirement to the pattern.
Recap
You modeled behavior with three patterns: Strategy to swap algorithms at runtime (classes or closures), Observer to broadcast state changes to decoupled listeners (the basis of PSR-14 dispatchers), and Command to turn requests into objects you can queue, log and undo (the basis of command buses). Together they keep collaboration flexible and responsibilities clear.
Frequently asked questions
Is the “Behavioral Patterns: Strategy, Observer, Command” lesson free?
Yes — the full text of “Behavioral Patterns: Strategy, Observer, Command” is free to read here on the web, and the PHP Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the PHP Academy course, upgrade to CoddyKit PRO.
What will I learn in “Behavioral Patterns: Strategy, Observer, Command”?
Model behavior and communication with behavioral patterns. You practise PHP Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start PHP Academy?
No prior experience is required. PHP Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Behavioral Patterns: Strategy, Observer, Command” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this PHP Academy lesson?
Yes. Every PHP Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- SOLID Principles in Practice
- Creational Patterns: Factory, Builder, Singleton
- Structural Patterns: Adapter, Decorator, Facade
- Behavioral Patterns: Strategy, Observer, Command