SOLID Principles Summary
Letter | Principle | Meaning |
---|---|---|
S | Single Responsibility Principle | A class should do one thing only and do it well |
O | Open/Closed Principle | Code should be open for extension, closed for modification |
L | Liskov Substitution Principle | Subclasses should be replaceable for their base classes |
I | Interface Segregation Principle | Clients shouldn’t be forced to depend on unused interfaces |
D | Dependency Inversion Principle | Depend on abstractions, not on concrete classes |
🔎 1. Single Responsibility Principle (SRP)
❌ Bad:
class User {
public function createUser() { /* ... */ }
public function sendWelcomeEmail() { /* ... */ }
}
✅ Good:
class UserService {
public function createUser() { /* ... */ }
}
class EmailService {
public function sendWelcomeEmail() { /* ... */ }
}
🔎 2. Open/Closed Principle (OCP)
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
Simple Example (BAD: Violates OCP)
class PaymentProcessor {
public function pay($type) {
if ($type === 'paypal') {
echo "Processing PayPal payment\n";
} elseif ($type === 'credit_card') {
echo "Processing Credit Card payment\n";
}
}
}
If you want to add a new method like Stripe, you have to modify the method. That breaks the principle.
✅ Better (Respects OCP with Interface and Polymorphism)
interface PaymentMethod {
public function pay();
}
class PayPal implements PaymentMethod {
public function pay() {
echo "Paying with PayPal\n";
}
}
class CreditCard implements PaymentMethod {
public function pay() {
echo "Paying with Credit Card\n";
}
}
class PaymentProcessor {
public function process(PaymentMethod $method) {
$method->pay(); // no change needed here to add new types!
}
}
// Usage
$processor = new PaymentProcessor();
$processor->process(new PayPal()); // Paying with PayPal
$processor->process(new CreditCard()); // Paying with Credit Card
To add Stripe:
class Stripe implements PaymentMethod {
public function pay() {
echo "Paying with Stripe\n";
}
}
// no need to change existing code in PaymentProcessor
🔎 3. Liskov Substitution Principle (LSP)
Objects of a superclass should be replaceable with objects of a subclass without breaking the app.
✅ Good:
interface Bird {
public function fly();
}
class Eagle implements Bird {
public function fly() {
echo "Flying high!";
}
}
If you later make a Penguin
(which can’t fly), you should not use Bird
— because that would break LSP.
🔎 4. Interface Segregation Principle (ISP)
No client should be forced to depend on methods it doesn’t use.
❌ Bad:
interface Worker {
public function work();
public function eat();
}
class Robot implements Worker {
public function work() {}
public function eat() {} // but robots don't eat!
}
✅ Good:
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
class Human implements Workable, Eatable {}
class Robot implements Workable {}
🔎 5. Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
❌ Bad (Tightly Coupled):
class MySQLConnection {
public function connect() { /* ... */ }
}
class UserRepository {
private $db;
public function __construct() {
$this->db = new MySQLConnection(); // tightly coupled
}
}
✅ Good (Using Dependency Injection + Interface):
interface DBConnectionInterface {
public function connect();
}
class MySQLConnection implements DBConnectionInterface {
public function connect() { /* ... */ }
}
class UserRepository {
private $db;
public function __construct(DBConnectionInterface $db) {
$this->db = $db;
}
}
✅ Summary Table
Principle | What it Helps With | Keywords |
---|---|---|
SRP | Maintainability | One responsibility per class |
OCP | Scalability, flexibility | Extendable, not modifiable |
LSP | Reliability | Replace parent with child safely |
ISP | Clean interfaces | Smaller, focused interfaces |
DIP | Loose coupling, testability | Abstractions, interfaces, DI |
Comments are closed.