Explain SOLID principles

 The SOLID principles are a set of five principles that help in designing software that's easy to maintain, extend, and scale. Let’s break down each principle with a simple PHP example to illustrate.

---
1. **Single Responsibility Principle (SRP)**

**Definition**: A class should have only one reason to change, meaning it should only have one job or responsibility.

**Example**: Let’s say we have a class `Invoice` that handles creating an invoice and sending it via email. This would violate SRP, as it has two responsibilities (creating and sending). Let’s split it into two classes.

```php
// Violating SRP
class Invoice {
    public function createInvoice() {
        // Code to create invoice
    }

    public function sendEmail() {
        // Code to send invoice email
    }
}
```

**Solution (Following SRP)**:

```php
class Invoice {
    public function createInvoice() {
        // Code to create invoice
    }
}

class EmailSender {
    public function sendEmail() {
        // Code to send email
    }
}
```

Now, each class has a single responsibility.

---
2. **Open/Closed Principle (OCP)**

**Definition**: Classes should be open for extension but closed for modification. You should be able to add new functionality without changing existing code.

**Example**: Let’s say we have a `PaymentProcessor` class that calculates discounts. To add new discount types, we can use inheritance or interfaces instead of modifying the existing class.

```php
// Violating OCP
class PaymentProcessor {
    public function calculateDiscount($type) {
        if ($type === 'percentage') {
            // Calculate percentage discount
        } elseif ($type === 'fixed') {
            // Calculate fixed discount
        }
    }
}
```

**Solution (Following OCP)**:

```php
interface Discount {
    public function calculate($amount);
}

class PercentageDiscount implements Discount {
    public function calculate($amount) {
        return $amount * 0.10; // 10% discount
    }
}

class FixedDiscount implements Discount {
    public function calculate($amount) {
        return $amount - 5; // $5 discount
    }
}
```

Now, we can add new discount types without modifying `PaymentProcessor`.

---
 

3. **Liskov Substitution Principle (LSP)**

**Definition**: Subclasses should be substitutable for their base classes without altering the correctness of the program.

**Example**: If we have a `Rectangle` class and create a `Square` subclass, it can violate LSP if `Square` behaves differently from `Rectangle`.

```php
class Rectangle {
    protected $width;
    protected $height;

    public function setWidth($width) {
        $this->width = $width;
    }

    public function setHeight($height) {
        $this->height = $height;
    }

    public function getArea() {
        return $this->width * $this->height;
    }
}

class Square extends Rectangle {
    public function setWidth($width) {
        $this->width = $width;
        $this->height = $width; // Problematic for LSP
    }

    public function setHeight($height) {
        $this->width = $height;
        $this->height = $height; // Problematic for LSP
    }
}
```

**Solution**: Avoid this by not making `Square` a subclass of `Rectangle`.

---

### 4. **Interface Segregation Principle (ISP)**

**Definition**: Clients should not be forced to depend on interfaces they do not use. It’s better to have more specific interfaces than a single general-purpose interface.

**Example**: Imagine an interface that forces classes to implement methods they don’t need.

```php
// Violating ISP
interface Worker {
    public function work();
    public function sleep();
}

class HumanWorker implements Worker {
    public function work() {
        // Work code
    }

    public function sleep() {
        // Sleep code
    }
}

class RobotWorker implements Worker {
    public function work() {
        // Work code
    }

    public function sleep() {
        // Robots don't sleep - violates ISP
    }
}
```

**Solution (Following ISP)**:

```php
interface Workable {
    public function work();
}

interface Sleepable {
    public function sleep();
}

class HumanWorker implements Workable, Sleepable {
    public function work() {
        // Work code
    }

    public function sleep() {
        // Sleep code
    }
}

class RobotWorker implements Workable {
    public function work() {
        // Work code
    }
}
```

Now `RobotWorker` is not forced to implement `sleep()`.

---
 

5. **Dependency Inversion Principle (DIP)**

**Definition**: High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.

**Example**: Let’s say we have a `Database` class that a `UserService` class depends on.

```php
// Violating DIP
class Database {
    public function connect() {
        // Connect to database
    }
}

class UserService {
    private $db;

    public function __construct() {
        $this->db = new Database(); // Tight coupling
    }
}
```

**Solution (Following DIP)**:

```php
interface DatabaseConnection {
    public function connect();
}

class MySQLConnection implements DatabaseConnection {
    public function connect() {
        // MySQL connection code
    }
}

class UserService {
    private $db;

    public function __construct(DatabaseConnection $db) {
        $this->db = $db;
    }
}
```

Now `UserService` depends on an interface rather than a specific class, which allows us to use any type of database connection (MySQL, PostgreSQL, etc.).

---

Following these principles can lead to cleaner, more maintainable, and extensible PHP code!

Comments