Menü schliessen
Created: April 7th 2025
Last updated: April 17th 2025
Categories: Php
Author: Ian Walser

SOLID Principles in PHP: The Ultimate Guide to Writing Clean, Scalable OOP Code

Donation Section: Background
Monero Badge: QR-Code
Monero Badge: Logo Icon Donate with Monero Badge: Logo Text
82uymVXLkvVbB4c4JpTd1tYm1yj1cKPKR2wqmw3XF8YXKTmY7JrTriP4pVwp2EJYBnCFdXhLq4zfFA6ic7VAWCFX5wfQbCC

Introduction

Whether you're just starting out in PHP or you're a seasoned developer aiming to sharpen your object-oriented programming (OOP) chops, mastering the SOLID principles can transform your codebase from spaghetti code into clean, maintainable architecture. In this guide, we'll dive deep into each of the SOLID principles—Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion—and demonstrate how to apply them effectively in PHP with clear, real-world examples.

By the end, you'll not only understand what each principle means but also how to write PHP code that scales better, tests easier, and follows industry-leading standards.

What Are the SOLID Principles?

SOLID is an acronym for five design principles that help software developers design better systems:

  • S – Single Responsibility Principle (SRP)
  • O – Open/Closed Principle (OCP)
  • L – Liskov Substitution Principle (LSP)
  • I – Interface Segregation Principle (ISP)
  • D – Dependency Inversion Principle (DIP)

S — Single Responsibility Principle (SRP)

Definition

A class should have only one reason to change, meaning it should only have one responsibility.

Bad Example

class User {
    public function saveToDatabase() {
        // save logic
    }

    public function sendEmail() {
        // email logic
    }
}

This class is responsible for both database and email logic. Violates SRP.

Refactored Example

class User {
    // user properties
}

class UserRepository {
    public function save(User $user) {
        error_log("User saved to DB.");
    }
}

class EmailService {
    public function send(User $user) {
        error_log("Email sent to user.");
    }
}

$repo = new UserRepository();
$email = new EmailService();

$repo->save(new User());
$email->send(new User());

Output (logically):

User saved to DB.
Email sent to user.

O — Open/Closed Principle (OCP)

Definition

Software entities should be open for extension but closed for modification.

Bad Example

class Payment {
    public function pay($type) {
        if ($type == 'paypal') {
            // PayPal logic
        } elseif ($type == 'stripe') {
            // Stripe logic
        }
    }
}

Refactored Using OCP

interface PaymentMethod {
    public function pay();
}

class PayPal implements PaymentMethod {
    public function pay() {
        echo "Paid using PayPal";
    }
}

class Stripe implements PaymentMethod {
    public function pay() {
        echo "Paid using Stripe";
    }
}

class PaymentProcessor {
    public function process(PaymentMethod $method) {
        $method->pay();
    }
}

// Usage:
$processor = new PaymentProcessor();
$processor->process(new Stripe());

Output:

Paid using Stripe

L — Liskov Substitution Principle (LSP)

Definition

Subtypes must be substitutable for their base types without altering the correctness of the program.

Bad Example

class Bird {
    public function fly() {
        echo "Flying";
    }
}

class Ostrich extends Bird {
    public function fly() {
        throw new Exception("Ostrich can't fly!");
    }
}

Substituting Ostrich breaks the program. Violates LSP.

Better Design

interface Bird {
    public function move();
}

class Sparrow implements Bird {
    public function move() {
        echo "Flying";
    }
}

class Ostrich implements Bird {
    public function move() {
        echo "Running";
    }
}

Output:

Flying
Running

I — Interface Segregation Principle (ISP)

Definition

Clients should not be forced to depend on interfaces they do not use.

Bad Interface

interface Worker {
    public function work();
    public function eat();
}

class Robot implements Worker {
    public function work() {
        echo "Robot working";
    }

    public function eat() {
        // Robots don't eat!
        throw new Exception("Robots don't eat");
    }
}

Refactored Interfaces

interface Workable {
    public function work();
}

interface Eatable {
    public function eat();
}

class Human implements Workable, Eatable {
    public function work() {
        echo "Human working";
    }

    public function eat() {
        echo "Human eating";
    }
}

class Robot implements Workable {
    public function work() {
        echo "Robot working";
    }
}

Output:

Human working
Human eating
Robot working

D — Dependency Inversion Principle (DIP)

Definition

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Without DIP

class MySQLConnection {
    public function connect() {
        // connect to DB
    }
}

class UserRepository {
    private $db;

    public function __construct() {
        $this->db = new MySQLConnection();
    }
}

Tightly coupled to MySQLConnection.

With DIP Applied

interface DBConnection {
    public function connect();
}

class MySQLConnection implements DBConnection {
    public function connect() {
        echo "Connected to MySQL";
    }
}

class UserRepository {
    private DBConnection $db;

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

    public function save() {
        $this->db->connect();
        echo "\nUser saved to DB.";
    }
}

// Usage:
$repo = new UserRepository(new MySQLConnection());
$repo->save();

Output:

Connected to MySQL
User saved to DB.

Benefits of Using SOLID in PHP Projects

  • ✅ Better testability
  • ✅ Loosely coupled code
  • ✅ Easier refactoring and maintenance
  • ✅ Cleaner architecture and separation of concerns
  • ✅ Scalable and readable codebase

Tips for Applying SOLID Principles in Real PHP Projects

  • Use design patterns like Factory, Strategy, and Adapter to complement SOLID.
  • Apply principles gradually—refactor over time rather than rewriting everything.
  • Use dependency injection tools like Symfony’s container or Laravel’s IoC container.
  • Write unit tests to ensure substitutability and contract consistency.

Conclusion

Mastering the SOLID principles will dramatically improve the quality of your PHP code. From cleaner separation of concerns to easier testing and enhanced scalability, these principles help you grow your codebase with confidence. Whether you're working on small scripts or enterprise-level applications, make SOLID your default mindset.