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

Open/Closed Principle

Code Quality 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 that automated detection is 'no' and that phpstan/psalm can flag structural patterns (e.g. growing switch/if-type chains), but these tools cannot reliably detect OCP violations as a general principle — they can only catch specific code patterns. Most violations require human code review to recognise that a method or class is being modified repeatedly for the same reason rather than extended.

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 replacing switch/if-else chains with polymorphism — introducing interfaces, creating new classes per type, and wiring them together. This is more than a one-line patch; it typically involves extracting an interface, creating multiple concrete implementations, and updating call sites, touching multiple files within a component but not necessarily a cross-cutting architectural rework.

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

Closest to 'persistent productivity tax' (b5). OCP applies across all contexts (web, cli, queue-worker) and its misapplication — either not applying it (growing switch chains) or over-applying it (premature abstraction) — slows down many work streams over time. It is not as load-bearing as shared mutable state or a global auth helper (b7), but its persistent influence on how new types and behaviours are added makes it a meaningful ongoing tax.

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 directly identifies the canonical wrong belief: developers think OCP means creating interfaces for every class upfront, when it is actually a reactive principle applied only after observed change. This is a well-documented gotcha (over-engineering via premature abstraction vs. under-engineering with growing switch chains) that most developers eventually learn but routinely get wrong initially.

About DEBT scoring →

Also Known As

OCP Open Closed Principle open for extension closed for modification

TL;DR

Classes should be open for extension but closed for modification — add behaviour without changing existing code.

Explanation

The O in SOLID, OCP states that you should be able to extend a class's behaviour without modifying its source code. In practice: use interfaces and polymorphism so new behaviour is added by writing a new class, not editing an existing one. A switch statement on a type field that grows every time a new type is added is a classic OCP violation — replace it with a polymorphic hierarchy. OCP reduces the risk that adding new features breaks existing tested behaviour.

Common Misconception

Applying OCP means creating an interface for every class upfront. OCP is applied in response to actual change — when a class has changed for the same reason twice, it is a signal to extract an abstraction that makes the next change an extension rather than an edit.

Why It Matters

Code that is open for extension but closed for modification can have new behaviour added without risking existing functionality — critical in shared libraries and stable APIs.

Common Mistakes

  • Adding a new case to a switch statement every time a new type is introduced — add a new class instead.
  • Modifying a method's internals to handle a new special case rather than using polymorphism.
  • Closing too early — abstracting before you know the variation points leads to wrong abstractions.
  • Not using interfaces as the seam for extension — concrete classes are harder to extend without modification.

Code Examples

✗ Vulnerable
// Must edit this class every time a new payment provider is added
class PaymentService {
    public function charge(string $provider, int $amount): void {
        if ($provider === 'stripe')  { /* Stripe SDK */ }
        elseif ($provider === 'paypal') { /* PayPal SDK */ }
        // Adding Braintree means editing this method
    }
}
✓ Fixed
interface PaymentGateway {
    public function charge(int $amount): ChargeResult;
}
class StripeGateway    implements PaymentGateway { public function charge(int $a): ChargeResult {} }
class PayPalGateway    implements PaymentGateway { public function charge(int $a): ChargeResult {} }
class BraintreeGateway implements PaymentGateway { public function charge(int $a): ChargeResult {} }

class PaymentService {
    public function __construct(private PaymentGateway $gateway) {}
    public function charge(int $amount): ChargeResult { return $this->gateway->charge($amount); }
    // Never changes when a new provider is added
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 73
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 1 ping S 0 pings S 2 pings M 0 pings T 1 ping W 1 ping T 1 ping F 6 pings S 2 pings S 3 pings M 1 ping T 2 pings W 0 pings T 0 pings 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 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 16 Amazonbot 10 Perplexity 8 Ahrefs 6 ChatGPT 4 Google 3 SEMrush 3 Unknown AI 2 Bing 2 Claude 1 Meta AI 1 Sogou 1 Qwen 1
crawler 54 crawler_json 4
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: High
⚡ Quick Fix
Replace switch/if-else chains that change when new types are added with polymorphism — add new behaviour by adding a new class, not editing existing ones
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
switch($type) or if($type==='x') patterns that grow every time a new type is added
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Class Tests: Update


✓ schema.org compliant