The SOLID Principles of Object-Oriented Design


S: Single Responsibility Principle (SRP)

The Single Responsibility Principle states that a class should have only one reason to change, meaning it should have one, and only one, job. This doesn't mean a class should only have one method, but rather that all its methods should serve a single, unified purpose. For example, your HttpController's job is to orchestrate a request, not to handle database logic or format HTML. By keeping classes focused—like having a UserRepository for database tasks and a View for rendering—you create a system that is easier to test, debug, and maintain, as changes to one responsibility (like the database schema) won't accidentally break another (like the view logic).


O: Open/Closed Principle (OCP)

The Open/Closed Principle is the core of a scalable architecture, asserting that software entities should be open for extension but closed for modification. Think of it as an electrical outlet in your wall: the socket is "closed" (you don't rip the wall open to plug in a new lamp), but it's "open" to any new appliance that fits the standard plug. In your architecture, the HttpController is the "wall socket," and ResolverInterface is its "plug." By depending on this abstract contract, you can add limitless new functionality (like an AdminRouter or BlogRouter) without ever touching the stable, tested HttpController code, effectively eliminating the risk of breaking what already works.


L: Liskov Substitution Principle (LSP)

The Liskov Substitution Principle states that objects of a superclass should be replaceable with objects of its subclasses without breaking the application. In simple terms, if a class Penguin inherits from Bird, it must be able to do everything a Bird can do. If your program has a makeBirdFly(Bird $b) method, passing it a Penguin object would break the program (as penguins can't fly), thus violating the principle. LSP enforces true "is-a" relationships, ensuring that child classes honor the parent's "contract" by not throwing new exceptions or returning unexpected types. This principle is what makes polymorphism reliable.


I: Interface Segregation Principle (ISP)

The Interface Segregation Principle advises that no client should be forced to depend on methods it does not use. Instead of one "fat" interface (like a GodInterface with 20 methods), you should prefer many small, cohesive "role interfaces" (e.g., ReadableInterface, WriteableInterface, DeletableInterface). This allows a class to implement only the functionality it actually provides—a read-only repository, for example, would only implement ReadableInterface. This principle prevents bloated classes, makes the system's "contracts" much clearer, and gives you greater flexibility in your implementations.


D: Dependency Inversion Principle (DIP)

The Dependency Inversion Principle is the foundational concept behind Dependency Injection and a decoupled architecture. It states that high-level modules (like your HttpController) should not depend on low-level modules (like a specific SmartyView or MySQLRepository). Instead, both should depend on abstractions (interfaces), like ViewInterface or UserRepositoryInterface. This "inverts" the typical dependency flow: the "details" (the concrete class) now depend on the "contract" (the interface), not the other way around. This allows you to swap out implementations—replacing SmartyView with TwigView—without the HttpController ever knowing or caring, making your application flexible, testable, and loosely coupled.

Shopping summary

Item

SubTotal: £

Empty Basket

this is a hidden panel

Completed in milliseconds

Full Script completed in 8 milliseconds

This is the top Panel

This is the bottom Panel