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

Open/Closed Principle — PHP Examples

Code Quality Advanced
debt(d7/e7/b7/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 explicitly state automated=no, and while phpstan and deptrac are listed, they cannot reliably detect OCP violations — growing switch/if chains and missing extension points require human architectural review to identify. There is no automated rule that flags 'this class should have been extensible.'

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes introducing a strategy or decorator pattern, but this typically means extracting an interface, creating multiple implementing classes, updating all call sites, and restructuring any DI or factory logic — changes that span multiple files and often multiple components. Common mistakes include switch statements on type that permeate multiple layers, making remediation cross-cutting by nature.

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

Closest to 'strong gravitational pull' (b7). OCP is an architectural design principle that applies to web, cli, and queue-worker contexts (all PHP contexts). Violations accumulate as structural debt — each new type added to a switch chain, or each configuration requiring a code change, compounds over time and shapes how every new feature must be added. The choice of whether to enforce extension points affects the entire codebase trajectory.

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

Closest to 'notable trap' (t5). The misconception field directly states the documented gotcha: developers believe 'open/closed means you should never modify existing code,' when the real meaning is that new behaviour should be addable via extension rather than editing existing logic. This is a well-known misread of the principle that most developers encounter and must consciously unlearn, but it does not fully contradict a similar concept — it is simply misread.

About DEBT scoring →

Also Known As

OCP extended plugin architecture extension without modification

TL;DR

Software entities should be open for extension but closed for modification — add new behaviour without editing existing, tested code.

Explanation

The Open/Closed Principle (OCP, the O in SOLID) means adding a new feature should require writing new code, not editing existing code and potentially breaking it. In PHP, OCP is achieved through: interface-based polymorphism (new payment gateways implement PaymentGatewayInterface without changing the PaymentService), strategy pattern (swap sorting algorithms by injecting a different Sorter), decorator pattern (add logging or caching by wrapping an existing service), and event/hook systems (fire an OrderPlaced event; new behaviour is added by registering listeners). The smell indicating OCP violation is a switch/match on a type tag that must be extended every time a new type is added — replace with polymorphism. Avoid premature OCP abstraction — only apply it where extension points are genuinely needed.

Common Misconception

Open/closed means you should never modify existing code. It means structuring code so new behaviour can be added via extension (new classes, new implementations) rather than editing existing logic — some modification is always necessary for bug fixes.

Why It Matters

The extended OCP perspective recognises that 'open for extension, closed for modification' applies at multiple scales — modules, packages, and services should be extensible without editing their internals.

Common Mistakes

  • Switch statements on type that grow with every new type — use polymorphism instead.
  • Configuration-driven behaviour that requires code changes to add new configurations — move to data.
  • Not designing extension points in libraries — callers need to monkey-patch instead of extending cleanly.
  • Misapplying OCP to stable, simple code — premature abstraction for extension is worse than a small switch.

Code Examples

✗ Vulnerable
// Must edit this switch every time a new format is added
function export(Report $r, string $format): string {
    return match($format) {
        'csv'  => exportCsv($r),
        'pdf'  => exportPdf($r),
    };
}
✓ Fixed
interface ReportExporter {
    public function export(Report $r): string;
}
// New formats: implement ReportExporter, register — no existing code changes

Added 15 Mar 2026
Edited 22 Mar 2026
Views 36
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 0 pings T 0 pings F 0 pings S 0 pings S 3 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W
Google 1
No pings yesterday
Amazonbot 6 Ahrefs 4 ChatGPT 4 Google 3 Scrapy 3 Unknown AI 2 Bing 2 Perplexity 1 Claude 1 Meta AI 1 Majestic 1
crawler 25 crawler_json 3
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: High
⚡ Quick Fix
When you find yourself opening a class to add an if/else for a new variant, introduce a strategy or decorator instead — the class should be extendable without modification
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
switch/if chains that grow with each new type; adding new payment method requiring modification of PaymentProcessor; new report format requiring changes to ReportGenerator
Auto-detectable: ✗ No phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Class Tests: Update


✓ schema.org compliant