← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Strategy Pattern

General PHP 5.0+ Intermediate
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no, and while phpstan/psalm are listed as tools, they cannot automatically flag the absence of a strategy pattern or the presence of switch/if-else branching on algorithm type — that requires a human reviewer recognising the code smell. The pattern's misuse (e.g. strategies coupled to context, or forgetting injection) is invisible to static analysers without custom rules.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes extracting the varying algorithm into an interface and creating one class per strategy — this means creating new files per strategy class, an interface, and updating the context to accept injection. This spans multiple files but is contained within one component rather than a cross-cutting codebase refactor.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The pattern applies across web, cli, and queue-worker contexts. When misapplied (e.g. too many trivial strategies, strategies coupled to context, or concrete-type coupling), it introduces ongoing friction in every work stream that touches that subsystem. However it doesn't define the system's entire shape, so b7/b9 would be too high.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly identifies the Strategy vs State confusion — both swap behaviour, and a competent developer unfamiliar with the distinction will conflate them. This is a well-documented gotcha that most developers eventually learn but frequently get wrong initially, matching the t5 anchor.

About DEBT scoring →

Also Known As

strategy policy pattern interchangeable algorithm

TL;DR

Defines a family of interchangeable algorithms behind a common interface, allowing the algorithm to be selected at runtime.

Explanation

The Strategy pattern encapsulates each algorithm in its own class implementing a common interface, making them interchangeable. The context class accepts a strategy via constructor injection and delegates behaviour to it. This eliminates switch/if-else chains that select algorithms (replacing switch smell with polymorphism), makes algorithms independently testable, and follows Open/Closed Principle — new strategies are added without modifying the context. Classic PHP examples: payment processors, sorting algorithms, and report formatters.

Common Misconception

Strategy and State patterns are interchangeable since both swap behaviour. Strategy objects are chosen by the client and remain stable. State objects transition themselves — the object changes its own behaviour based on internal state transitions without the client selecting which strategy to use.

Why It Matters

The Strategy pattern defines a family of interchangeable algorithms — swapping behaviour at runtime without conditionals, making it easy to add new strategies without modifying existing code.

Common Mistakes

  • Strategies that depend on the context object — they should be independent algorithms.
  • Too many strategies for trivial variations — a simple parameter is cleaner than a strategy class.
  • Not using interfaces for strategies — callers become coupled to concrete strategy types.
  • Forgetting to inject the strategy — instantiating it inside the context defeats the purpose.

Code Examples

✗ Vulnerable
function sortUsers(array $users, string $by): array {
    if ($by === 'name') {
        usort($users, fn($a,$b) => strcmp($a->name, $b->name));
    } elseif ($by === 'age') {
        usort($users, fn($a,$b) => $a->age <=> $b->age);
    } elseif ($by === 'score') {
        usort($users, fn($a,$b) => $b->score <=> $a->score);
    } // must edit this function for every new sort
    return $users;
}
✓ Fixed
interface SortStrategy {
    public function compare(User $a, User $b): int;
}

class SortByName  implements SortStrategy { public function compare(User $a, User $b): int { return strcmp($a->name, $b->name); } }
class SortByAge   implements SortStrategy { public function compare(User $a, User $b): int { return $a->age <=> $b->age; } }
class SortByScore implements SortStrategy { public function compare(User $a, User $b): int { return $b->score <=> $a->score; } }

function sortUsers(array $users, SortStrategy $strategy): array {
    usort($users, $strategy->compare(...));
    return $users;
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 50
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 3 pings F 2 pings S 2 pings S 3 pings M 1 ping T 0 pings W 1 ping T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 0 pings W
No pings yet today
PetalBot 1
Scrapy 11 Amazonbot 6 Google 6 Perplexity 5 Ahrefs 4 ChatGPT 4 Bing 3 SEMrush 3 Unknown AI 2 Claude 2 Meta AI 1 PetalBot 1
crawler 40 crawler_json 8
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Extract the varying algorithm into an interface, create one class per strategy, inject the chosen strategy — eliminates the switch/if-else that changes every time a new algorithm is added
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
switch($algorithm) or if($type==='stripe') branching on algorithm choice in the middle of business logic
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update


✓ schema.org compliant