Categories
The SOLID principles of object-oriented design
SOLID is an acronym representing a set of five design principles to make software design more understandable, flexible, and maintainable. These principles were introduced by Robert C. Martin and are widely used in object-oriented programming. Let’s dive into these principles with explanations and examples using PHP:
1. Single Responsibility Principle (SRP)
- Definition: A class should have only one reason to change, meaning it should have only one job or responsibility.
- Concept: Encourage creating classes that have only one functionality.
// Violating SRP
class UserManager {
public function createUser() {
// code to create a user
}
public function logError($error) {
// code to log error
}
}
// Complying with SRP
class UserManager {
public function createUser() {
// code to create a user
}
}
class Logger {
public function logError($error) {
// code to log error
}
}
2. Open/Closed Principle (OCP)
- Definition: Software entities should be open for extension but closed for modification.
- Concept: You should be able to add new functionality without changing existing code.
// Violating OCP
class Rectangle {
public $width;
public $height;
}
class AreaCalculator {
public function calculate($rectangle) {
return $rectangle->width * $rectangle->height;
}
}
// Complying with OCP
interface Shape {
public function area();
}
class Rectangle implements Shape {
public $width;
public $height;
public function area() {
return $this->width * $this->height;
}
}
class Circle implements Shape {
public $radius;
public function area() {
return pi() * pow($this->radius, 2);
}
}
class AreaCalculator {
public function calculate(Shape $shape) {
return $shape->area();
}
}
3. Liskov Substitution Principle (LSP)
- Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.
- Concept: Objects of a superclass should be replaceable with objects of a subclass without affecting the program’s correctness.
// Violating LSP
class Bird {
public function fly() {
// code for flying
}
}
class Penguin extends Bird {
public function fly() {
// Penguins can’t fly!
throw new Exception('Can’t fly');
}
}
// Complying with LSP
interface Bird {
public function move();
}
class Sparrow implements Bird {
public function move() {
// code for flying
}
}
class Penguin implements Bird {
public function move() {
// code for walking
}
}
4. Interface Segregation Principle (ISP)
- Definition: Clients should not be forced to implement interfaces they do not use.
- Concept: Instead of having a bloated interface, split it into smaller and more specific ones so that the clients will only have to know about the methods that are of interest to them.
// Violating ISP
interface Worker {
public function work();
public function eat();
}
class HumanWorker implements Worker {
public function work() {
// working
}
public function eat() {
// eating
}
}
// Complying with ISP
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
class HumanWorker implements Workable, Eatable {
public function work() {
// working
}
public function eat() {
// eating
}
}
5. Dependency Inversion Principle (DIP)
- Definition: Depend on abstractions, not on concretions.
- Concept: High-level modules should not depend on low-level modules but should depend on abstractions. Also, abstractions should not depend on details. Details should depend on abstractions.
// Violating DIP
class LightBulb {}
class Switch {
private $bulb;
public function operate(LightBulb $bulb) {
$this->bulb = $bulb;
// operate the light bulb
}
}
// Complying with DIP
interface Switchable {
public function operate();
}
class LightBulb implements Switchable {
public function operate() {
// turn on/off the light bulb
}
}
class Switch {
private $device;
public function operate(Switchable $device) {
$this->device = $device;
$this->device->operate();
}
}