Originally published on phpdesignpatterns.dev — part of the PHP design patterns course. View this lesson on the original site.
Class, closure, or config map: pick the lightest fit
Strategy doesn't have to be one interface and N classes. Three common shapes show up in PHP, and picking the right one keeps the pattern from feeling heavyweight.
Variant 1 — Class per strategy (the canonical shape)
The version we built in lesson 2.4. Best when:
- each strategy has any non-trivial logic
- strategies need their own constructor dependencies
- strategies will grow over time
Cost: one file per strategy.
Variant 2 — Closures as strategies
If each strategy is a one-liner, classes are overkill:
<?php
$discounts = [
'guest' => fn (int $total) => 0,
'standard' => fn (int $total) => $total > 5000 ? (int) round($total * 0.05) : 0,
'loyalty' => fn (int $total) => (int) round($total * 0.10),
'employee' => fn (int $total) => (int) round($total * 0.40),
];
$discount = $discounts[$customerType] ?? fn () => 0;
$amount = $discount($totalInPence);
Best when the rules are genuinely simple, the set is small, and you're inside one file. As soon as a rule grows beyond a few lines or needs dependencies, promote it to a class.
Variant 3 — Config-driven strategies
When the variation is purely numeric, a class per rule is overkill — a data structure does the job:
<?php
const DISCOUNT_RATES = [
'guest' => 0.00,
'standard' => 0.05,
'loyalty' => 0.10,
'loyalty_plus' => 0.15,
'employee' => 0.40,
];
$rate = DISCOUNT_RATES[$customerType] ?? 0.00;
$discount = (int) round($totalInPence * $rate);
This isn't really Strategy any more — it's a lookup. That's the point. If your variation is just a number that changes by case, you don't need a pattern; you need a map.
How to choose
| Signal | Use |
|---|---|
| Rules are non-trivial (multiple lines, conditions, dependencies) | Class per strategy |
| Rules are one-liners with no setup | Closures |
| Rules differ only in a value (a rate, a limit, a flag) | Config map |
| Mix of trivial and non-trivial | Class per strategy — keep it consistent |
The mistake to avoid is starting with config-map for simplicity, then bolting on logic when the rules grow. The config map silently becomes a mini interpreter. Promote it to classes the moment a rule needs branching of its own.
From PHP design patterns — Strategy: replacing branching with swappable behaviour