If you want to write clean, maintainable, and scalable PHP code, understanding SOLID principles is a must. These five principles, introduced by Robert C. Martin (Uncle Bob), help developers design software that is easy to understand, extend, and test. In this guide, we’ll break down each SOLID principle with simple explanations and PHP examples.
What Are SOLID Principles?
SOLID is an acronym for:
- 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)
By following these principles, you can build PHP applications that are easier to maintain and extend.
Single Responsibility Principle (SRP) in PHP: Writing Maintainable Code
A class should have only one reason to change. This means a class should have only one job or responsibility.
❌ Bad Example:
class Report
{
public function generateReport()
{
return "Report content";
}
public function saveToFile($content)
{
file_put_contents('report.txt', $content);
}
}
Here, the Report
class is handling both report generation and file storage, which violates SRP.
✅ Good Example:
class Report
{
public function generateReport()
{
return "Report content";
}
}
class FileStorage
{
public function saveToFile($content)
{
file_put_contents('report.txt', $content);
}
}
Now, each class has a single responsibility.
Open/Closed Principle (OCP) in PHP: Enhancing Code Flexibility
Software entities should be open for extension but closed for modification. This means you should be able to extend a class’s behavior without modifying its existing code.
❌ Bad Example:
class PaymentProcessor
{
public function payWithCreditCard()
{
return "Paid with Credit Card";
}
}
What if we need to add a PayPal payment option? We would have to modify this class, violating OCP.
✅ Good Example:
interface PaymentMethod
{
public function pay();
}
class CreditCardPayment implements PaymentMethod
{
public function pay()
{
return "Paid with Credit Card";
}
}
class PayPalPayment implements PaymentMethod
{
public function pay()
{
return "Paid with PayPal";
}
}
class PaymentProcessor
{
public function processPayment(PaymentMethod $paymentMethod)
{
return $paymentMethod->pay();
}
}
Now, we can easily add new payment methods without modifying existing code.
Liskov Substitution Principle (LSP) in PHP: Ensuring Code Reusability
Subtypes must be substitutable for their base types without altering the correctness of the program.
❌ Bad Example:
class Bird
{
public function fly()
{
return "Flying";
}
}
class Penguin extends Bird
{
public function fly()
{
throw new Exception("Penguins can't fly!");
}
}
Here, Penguin
extends Bird
but does not support flying, violating LSP.
✅ Good Example:
interface Bird
{
public function move();
}
class FlyingBird implements Bird
{
public function move()
{
return "Flying";
}
}
class WalkingBird implements Bird
{
public function move()
{
return "Walking";
}
}
Now, each class follows LSP properly.
Interface Segregation Principle (ISP) in PHP: Designing Efficient Interfaces
A class should not be forced to implement interfaces it does not use.
❌ Bad Example:
interface Worker
{
public function work();
public function eat();
}
class Robot implements Worker
{
public function work()
{
return "Working";
}
public function eat()
{
throw new Exception("Robots don’t eat!");
}
}
Here, Robot
is forced to implement eat()
, which doesn’t make sense.
✅ Good Example:
interface Workable
{
public function work();
}
interface Eatable
{
public function eat();
}
class HumanWorker implements Workable, Eatable
{
public function work()
{
return "Working";
}
public function eat()
{
return "Eating";
}
}
class RobotWorker implements Workable
{
public function work()
{
return "Working";
}
}
Now, classes only implement methods they need.
Dependency Inversion Principle (DIP) in PHP: Improving Code Scalability
High-level modules should not depend on low-level modules. Both should depend on abstractions.
❌ Bad Example:
class MySQLDatabase
{
public function connect()
{
return "Connected to MySQL";
}
}
class UserRepository
{
private $database;
public function __construct()
{
$this->database = new MySQLDatabase();
}
}
Here, UserRepository
is tightly coupled to MySQLDatabase
.
✅ Good Example:
interface DatabaseConnection
{
public function connect();
}
class MySQLDatabase implements DatabaseConnection
{
public function connect()
{
return "Connected to MySQL";
}
}
class UserRepository
{
private $database;
public function __construct(DatabaseConnection $database)
{
$this->database = $database;
}
}
Now, we can swap database implementations without modifying UserRepository
.
Conclusion
By applying SOLID principles in PHP, you make your code more maintainable, scalable, and testable. Whether you’re working on a small project or a large application, these principles will help you write better software.
You’ve now mastered the SOLID principles in PHP—why not take your skills further? Check out Understanding PHP Object-Oriented Programming (OOP) to see how these principles come to life in real-world applications! 🚀