Open/Closed Principle
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
}
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
34
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 8
Amazonbot 8
Ahrefs 4
Google 3
Unknown AI 2
ChatGPT 2
Also referenced
How they use it
crawler 25
crawler_json 2
Related categories
⚡
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