teckut.com

solid principles

SOLID Principles in Programming are five fundamental design rules that help developers write clean, maintainable, and scalable code.

Have you ever looked at a project you wrote six months ago and felt like you were reading a foreign language? Or changed one small function and suddenly the entire website crashed? This is what developers call spaghetti code—code that is tightly coupled, hard to understand, and even harder to maintain.

To avoid this chaos, experienced developers rely on the SOLID principles, a set of five proven design rules that bring structure, flexibility, and clarity to software development.

.

The History: Why SOLID Principles Were Created

In the early days of programming, code was “procedural”—huge files where one class did everything. This led to a nightmare scenario:

  • Small changes = 10 new bugs.
  • Adding features = absolute fear.
  • Testing = impossible.

Around the early 2000s, Robert C. Martin (Uncle Bob) summarized five Object-Oriented Programming (OOP) practices into the acronym SOLID. His goal was simple: Make code easy to change, test, and extend without breaking existing things.

Case Study: Applying SOLID Principles in the Geometry App

To understand these 5 rules, we will use one consistent theme: A Geometry App for Architects. We need this app to calculate areas, handle different shapes, and print reports. Without SOLID Principles, this app would be a mess. With SOLID Principles, it becomes a professional tool.

S – Single Responsibility Principle (SRP) in SOLID Principles

“A class should have one job, and only one reason to change.”

In our Shape app, imagine a Square class. Should it know how to calculate its area and how to output the result as HTML?

The Problem

class Square {
    public $length;

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

    // ❌ SRP violation: business logic + presentation logic together
    public function printFormattedArea() {
        echo "<div>The area is: " . $this->getArea() . "</div>";
    }
}

Why this is bad: If your boss asks you to change the <div> tag to an <h1>, you have to edit the Square class. A “Shape” class shouldn’t care about “HTML.” If you change your UI, you shouldn’t have to touch your math logic.

The Solution: The Specialist Approach

We split the responsibilities into two “specialist” classes.

class Square {
    public $length;

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

class ShapePrinter {
    public function renderHtml($area) {
        return "<div>The area is: $area</div>";
    }
}

Now, the Square class is only for math, and the ShapePrinter is only for display.

O: Open/Closed Principle (OCP)

“Open for extension, closed for modification.”

You should be able to add new features (extension) without changing the code you already wrote (modification).

The Problem
Imagine your app currently only handles Squares. Suddenly, your client wants to add Circles.

class AreaCalculator {
    public function sum($shapes) {
        $area = [];

        foreach ($shapes as $shape) {
            if (is_a($shape, 'Square')) {
                $area[] = $shape->length ** 2;
            }
            // If we add Circle, we have to come back here and add an 'else if'
            // That means we are MODIFYING this file every single time.
        }

        return array_sum($area);
    }
}

The Solution: The Interface Strategy

We create a Contract (Interface). We tell the calculator: “I will give you a list of objects. I don’t care what they are, as long as they follow the area() rule.”

interface ShapeInterface {
    public function area();
}

class Square implements ShapeInterface {
    public $length;

    public function area() {
        return $this->length ** 2;
    }
}

class Circle implements ShapeInterface {
    public $radius;

    public function area() {
        return pi() * ($this->radius ** 2);
    }
}

class AreaCalculator {
    public function sum(array $shapes) {
        $area = [];

        foreach ($shapes as $shape) {
            // It just works for any shape that implements the interface!
            $area[] = $shape->area();
        }

        return array_sum($area);
    }
}


L: Liskov Substitution Principle (LSP)

“Subtypes must be substitutable for their base types.”

This is a fancy way of saying: Don’t lie. If Class B is a child of Class A, you should be able to use Class B anywhere you use Class A without the program crashing.

The Problem: The Square-Rectangle Dilemma

In math, a Square is a type of Rectangle. But in code:

  • A Rectangle has setWidth(w) and setHeight(h).
  • A Square forces width and height to always be equal.

If a user writes code expecting a Rectangle and sets the width to 10 and height to 20, they expect an area of 200. If you “substitute” a Square, the area becomes 400 (because the square forced the height to match the width). The logic is now broken.

The Lesson: If a child class cannot fulfill the “promises” made by the parent class, do not use inheritance.

I: Interface Segregation Principle (ISP)

“Don’t force a class to implement things it doesn’t need.”

What if we want our architects to calculate the Volume of 3D shapes like Cubes?

The Problem: The “Fat” Interface

interface ShapeInterface {
    public function area();
    public function volume(); // We added this to the main interface
}

class Square implements ShapeInterface {
    public function area() {
        return 25;
    }

    public function volume() {
        return null; // ERROR: A flat square doesn't have volume!
    }
}

The Square is being forced to implement volume(), which makes no sense for a 2D shape.

The Solution: Specific Interfaces

interface ShapeInterface {
    public function area();
}

interface ThreeDimensionalInterface {
    public function volume();
}

class Cube implements ShapeInterface, ThreeDimensionalInterface {
    public function area() {
        /* ... */
    }

    public function volume() {
        /* ... */
    }
}

class Square implements ShapeInterface {
    public function area() {
        /* ... */
    }
}

D: Dependency Inversion Principle (DIP)

“Depend on abstractions (interfaces), not on concrete classes.”

This is about “Decoupling.” Your high-level logic should not be “glued” to a specific tool.

The Problem

If your ShapeManager is hard-coded to use a specific LegacyPrinter class, you are stuck. To change to a ModernPrinter, you have to rewrite the ShapeManager.

The Solution: Dependency Injection

interface PrinterInterface {
    public function print($data);
}

class ModernPrinter implements PrinterInterface {
    public function print($data) {
        /* ... */
    }
}

class ShapeManager {
    private $printer;

    // We ask for the "PrinterInterface" (the abstraction)
    // We don't care if it's a ModernPrinter, LegacyPrinter, or PDFPrinter.
    public function __construct(PrinterInterface $printer) {
        $this->printer = $printer;
    }
}

Summary: Junior vs. Professional Code

PrincipleJunior Way (Anti-Pattern)Professional Way (SOLID Principles)
SRPOne class does everything.One class = One job.
OCPUsing if/else for every new feature.Using Interfaces to add features.
LSPForcing inheritance where it doesn’t fit.Only inherit when behavior is identical.
ISPOne giant interface with 20 methods.Multiple small, specific interfaces.
DIPCreating objects inside classes (new MyClass).Injecting dependencies via constructors.

Why does this make you a SOLID Developer?

By applying these 5 rules to your next PHP project, you gain three massive advantages:

  • Maintenance: When a bug appears in the area of math, you only check the Shape class, not the printer or the database classes
  • Teamwork: You can work on the Circle logic while your teammate works on the JSONExport logic without ever touching the same file
  • Testing: You can test the AreaCalculator by giving it a “Mock” shape, making your PHPUnit tests fast and reliable.

Ready to start? When building scalable WordPress plugins, following SOLID Principles helps keep code clean and maintainable.

If you are just starting with plugin development, check out our WordPress plugin development guide

Leave a Reply

Your email address will not be published. Required fields are marked *