Could we help you? Please click the banners. We are young and desperately need the money
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.
SOLID is an acronym for five design principles that help software developers design better systems:
A class should have only one reason to change, meaning it should only have one responsibility.
class User {
public function saveToDatabase() {
// save logic
}
public function sendEmail() {
// email logic
}
}
This class is responsible for both database and email logic. Violates SRP.
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.
Software entities should be open for extension but closed for modification.
class Payment {
public function pay($type) {
if ($type == 'paypal') {
// PayPal logic
} elseif ($type == 'stripe') {
// Stripe logic
}
}
}
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
Subtypes must be substitutable for their base types without altering the correctness of the program.
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.
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
Clients should not be forced to depend on interfaces they do not use.
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");
}
}
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
High-level modules should not depend on low-level modules. Both should depend on abstractions.
class MySQLConnection {
public function connect() {
// connect to DB
}
}
class UserRepository {
private $db;
public function __construct() {
$this->db = new MySQLConnection();
}
}
Tightly coupled to MySQLConnection.
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.
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.