What It Is
The Strategy pattern makes an algorithm swappable: the surrounding code stays the same, and the interchangeable part — how to price, how to sort, how to compress — is plugged in as a value.
PHP makes this light: closures are first-class values, so a strategy is often just a Closure in a property. No interface, no extra class — assign a different closure and the behavior changes.
Example: Swappable Pricing
checkout() never changes; the pricing rule is a closure in a property. Regular price, Black Friday, member discount — three closures, one shop.
The strategy is a closure
Three checkouts of the same 50 give three totals — only the assigned closure differs. This is also how usort works: you hand it the comparison strategy.
Output: PHP script
<?php
// The strategy is just a closure in PHP.
class Shop {
public function __construct(public \Closure $pricing) {}
public function checkout(float $price): void {
printf("total: %.2f\n", ($this->pricing)($price));
}
}
$regular = fn(float $p): float => $p;
$blackFriday = fn(float $p): float => $p * 0.7;
$member = fn(float $p): float => $p - 5;
$shop = new Shop($regular);
$shop->checkout(50);
$shop->pricing = $blackFriday;
$shop->checkout(50);
$shop->pricing = $member;
$shop->checkout(50);
When to Use It
Use it whenever an algorithm varies while its surroundings do not: pricing rules, retry policies, sorting orders, validation modes.
Skip it when there is one algorithm and no realistic second. Use an interface with classes instead of a closure only when a strategy needs its own state or several methods.
Pros and Cons
Pros: behavior swaps at run time; each strategy is small and testable alone; in PHP it is nearly free — a closure and an assignment.
Cons: the chosen strategy is invisible at the call site — debugging means finding what was assigned; too many micro-strategies fragment simple logic.