The 5 SOLID principles with examples [in PHP]

Coding (Php 7.x)


Do you want to learn all about Object Oriented Programming? This post you will see examples of the 5 solid principles developed by uncle bob
 
/img/blog/solid-principles-in-objected-oriented-programming-with-examples-php.jpg

Introduction

What does it mean to be a good programmer?

 

If you are a European sports-lover you surely know that Cristiano Ronaldo is currently the best football player in the world (top 3 at least), if you are American and you love car racing you surely know Richard Petty and Jimmie Johnson, for an Asian audience Yokozuna Hakuho might be a notable name.

 

There are a lot of factors that are included in those examples but most important there is data.

 

For developers though, it is not that simple.

 

Everyone with a bit of experience in coding sees good programmers from a different standpoint.

 

I have met CTO for which the years of experience you have in a determined language is not very important, they prefer soft skills, others will evaluate according to the number of PHP function you know by heart, the companies with lazy management will test your skills via automated skill testing online (that in my point of view are just a scam and do not actually test any skill at all).

 

As a web developer myself, In my career, I came across dozens of developers and seen thousands of lines of code and when I need to evaluate a developer skill I mainly look at two factors.

 

How easy is to read their code and how likely is that their code will work and scale a year from now.

 

Luckily, there are some fundamentals, or principles that make it easy to be better in coding.

 

We have already talked about the MVC principle a few posts ago.


In this post will see other principles of web development

 

The S.O.L.I.D. principles were invented by Robert C. Martin.

 

He is a software engineer and instructor. 

 

He was one of the authors of the Agile Manifesto and for developing several software design principles including the ones in the SOLID.

 

S.O.L.I.D. is a set of 5 principles that aim to make your code more readable and easy to refactor.

 

Mr. Martin came up with this idea in the late ‘90s.

 

The majority of the principles Martin has promoted during the years were invented by himself. 

 

Anyway, the Liskov substitution principle and the Open–closed principle, that you will see below were devised with Barbara Liskov and Bertrand Meyer.

Curiosity the solid acronym was actually introduced by Michael Feathers not Mr. Martin

 

The goal of SOLID is to help you create code that will work fine in the long-term not only after the next deployment to production.

 

The reason SOLID is extremely important in PHP is that this language is a class-based language, thus, using SOLID principles will result in better code.


“The final goal of your code is to work and be easy to reason about”
 

 

Why S.O.L.I.D.?


There are several reasons SOLID is a good gauge when measuring the “beauty” of the code in a web application,

 

all of them have to do with the bad of PHP rather than the good of solid principles themselves.

 

Spaghetti code


Spaghetti is undoubtedly the most famous type of pasta in the world, an ancient second-hand dish from Bahawalpur’s kitchen that arrived in Italy thanks to the famous explorer Marco Polo and quickly became the favorite food among the population.

 

Almost every recipe that includes spaghetti (either with meat, vegetable or seafood) is incredibly easy to make.

 

That twisted goodness in coding has a much less appealing taste. 

 

As it is very difficult to find the start and the end of the same thread of pasta a web application with spaghetti code is very complicated to work with.

 

Especially when there are too many dependencies instead of using flexible interfaces available in OOP

 

Rigidity


How many times did you write some lines somewhere in your application to find out that your code broke down?

 

This is what Robert C. Martin calls rigidity, 

 

There are ways to solve this problem with Unit and functional tests but the best way in at its root when you write the code.

 

Each part of your code should not be hardly bond with other parts. 

 

If one change affects other parts of the code there is only a keyword for you.

 

Refactor!

 

 

Fragility


Fragility and rigidity as somehow related, 

 

Both are caused by new code inserted into the application and both have the same symptoms with are seen in errors and warning. 

 

But fragility is more difficult to spot, sometimes it can happen that you deploy some code and you find out about problems days later, 

 

The reason is that the error is unrelated and in two different part of the application,

 

That is what is called fragility.

 


Immobility


The last problem that we often see in and Objected-oriented project is immobility,

 

You have immobility when you feel that sense of Deja Vu, that sensation that you have already written the same feature or snippet before and when you try to reuse the previous code instead of writing a new one it does not work.

 

That happens because the code is bound in a specific context instead of being loose and only takes care of his duty.

 

Before dive into what are the SOLID principle make sure you know the basics of PHP language in order to have a clear comprehension of the examples below.

 

 

How to write code according to S.O.L.I.D. principles?

 

Let’s start with a warning: writing code in SOLID style means writing more code that you are used to.

 

If you write using SOLID you will spend more time writing code to create the structure of your web application.

 

The good news is that in the long term you’ll need half of the time reading and trying to understand the code you wrote.

 

So let’s start with the 5 SOLID principles:

 


Single-responsibility principle

 

SRP states that: A class should have only one reason to change

 

To understand this do a little exercise, 

 

look at the last PHP class you have worked on and write down a sentence that defines its role in the web application.

 

Done? 

 

If you used the conjugation "and" or you have used "or" it is time to refactor, that class is not using the first principle of SOLID.

 

Each class needs to be in charge of only one functionality, and your method only processes a single task at a time.

 

Let’s have a look at this example:
 

class UserRegistrationController
{
    public function register(Request $request, Response $response)
    {
        $user = $this->createUser($request);
		
        $this->database->query("insert into users ...");

        $this->email
            ->to($user->email())
            ->subject("Welcome")
            ->send();

        return $this->successfulResponse($response)
    }
}

 

In the snippet above we have a controller that should be in charge of registering a new user,

 

It does it ...

... plus it communicates with the database running a query than it is sending an email to the user.

 

Way too much stuff for a single method.

 

How can we improve it?
 

class UserRegistration
{
    public function __construct(
        RegistrationStorage $storage
        RegistrationEmail $email
    ) 
    {
        $this->storage = $storage;
        $this->email = $email;
    }

    public function register(User $user)
    {
        $this->storage->save($user);
        $this->email->sendTo($user);
    }
}

 

What changed?

 

To begin with the class, we now defined two classes when we instantiate the object and those two classes are including their own logic, one is in charge of saving data to the database another of sending emails.

 

Regarding the register method, it is now much cleaner and easier to read, it is actually written in plain English, 

 

you won’t even need 2 seconds to understand what this method is doing.

 

The only task of the class is to register the user, talking with the database and sending email is not, and it shouldn’t be its business.

 

Open-closed principle

 

Software entities should be open for extension but closed for modification

 

Let’s deconstruct the sentence:

 

Software entities, in this case, are our classes.

 

They should be open for extension,

 

That’s a tricky one, we can extend the behavior of our classes in PHP using the relative keywords extends, 

 

So the open-closed principle is about inheritance?

 

Solid is not about PHP, it about writing programs and several programming languages are not able to extend their classes, some of them do not even have classes. 

 

The open-closed principle is not about inheritance, it is about a composition a building block in a object-oriented design.

 

It is the idea that we should be able to abstract features that differ between components and compose them into separate units.
 

abstract class Duck 
{
    public function swim(){...}
    public function quack(){...}
    public function fly(){...}
}

class CityDuck extends Duck {...}
class WildDuck extends Duck {...}
class RubberDuck extends Duck {...}
class WoodenDuck extends Duck {...}

 

In this code, we have an abstract class with some methods that define how a duck swim, quack, and fly, and we extend the behavior of this class to other classes.

 

Classes of a specific type of ducks,  a tamed one and a wild one for example,

 

All work fine up to this point until we arrive at the instantiation of the rubber and the wooden ones.

 

As you can imagine the behavior for those two classes is quite different, they do not swim, they only float, they do not quack (alright the rubber one squeak when squeezed) and they definitely do not fly.

 

This is a common problem and one for the reason there is a debate about the use of composition over inheritance.


How can we translate this code and made it use composition instead of inheritance?
 

interface Swimming { public function swim(); }
interface Quacking { public function makeNoise(); }
interface Flying { public function fly(); }

class WildDuck implements Quacking {
    public function makeNoise() {
        $this->quacking->makeNoise();
    }
}

class RubberDuck {
    function __construct (
        Swimming $swimming,
        Quacking $quacking,
        Flying $flying
    )
    {
        $this->swimming = $swimming;
        $this->quacking = $quacking;
        $this->flying = $flying;
    }
    
    public function quack () 
    {
        $this->quacking->makeNoise();
    }
}

We start with another plan, this time we create interfaces for each of the features that a duck should have (note that this time we are saying that a duck "has" instead of duck "is").

 

Eventually, in our class we can pass the interfaces in the constructor and use the parameter within the methods of the class.

 

To explain what is the advantage of all of that and how to comply with the open-closed principle we now add another feature to our Ducks.

 

Let’s say that instead of quacking we want our beloved rubber ducks to squeak. 
 

class Squeaking implements Quacking () 
{
    public function makeNoise(){}
}
New RubberDuck(new Swimming, new Squeaking, new Flying);

 

Now we instantiate RubberDuck, and passed the new Squeaking class to the controller, we have just changed his behavior, now the quack method will provide a different result, without actually change the code inside the class.

 

What you have seen is in a way a similar behavior of a design pattern called Strategy Pattern.

 

 


Another way you can implement this is by using another famous and quite easy design pattern the Decorator design pattern
 

 

Liskov substitution principle


An object in a program should be replaceable with instances of their subtypes without altering the correctness of that program

 

The story of Barbara Liskov is quite interesting, born in Los Angeles in 1939, she has attended Stanford and got a Ph.D. in computer science in a world where this course of study was for the majority a male environment.

 

She became one of the first in America to get this degree and later on in her career start to teach at the computer science department at MIT.

 

She is famous for a principle that she and Jeanette Wing developed.

 

The official principle says that :

 

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

 

As you can see the explanation is quite straightforward (you just need a degree in Mathematics or Rocket science)

 

Jocking aside let’s deconstruct this sentence and see what it actually means.

 

The goal of this principle is to let you decide whether you can use inheritance in your design or you must prefer composition.

 

To make things more clear will keep the duck example:

 

T is the Duck class

S is the WildDuck class that inherits from the duck class

 

Let Φ(x) be a property provable about objects x of type Duck. Then Φ(y) should be true for objects y of type WildDuck where WildDuck is a subtype of Duck.

 

Already a little improvement here but we can do better.

 

Now y is Donald a duck that lives wildly in a pond

x is Daisy another duck she is instantiated as a Duck not wild, not domestic.

Φ is the capability of a Donald to swim (it is represented as a method in PHP)


Let the ability to swim be a property provable about objects Daisy of type Duck. Then swimming should be true for objects Donald of type WildDuck where WildDuck is a subtype of Duck.

 

You need to think at this sentence when you are creating inheritance in your code.

 

Is this sentence always true?

 

In this case the answer no. 

 

What if a year from now we are going to instantiate Duckie a rubber duck that needs to fit into our software?

 

Now the principle is not true anymore, Duckie is not able to swim,

 

That the signal that in this case, you need to prefer composition over inheritance

 

This concept is closely related to the one of Design by contract I advise to have a look at it to make everything clearer.


 

Interface segregation principle


Many client-specific interfaces are better that one general-purpose interface

 

This principle was first developed by Mr. Robert Martin when he was a software engineer at Xerox.

 

They have an interface called job and this interface was in charge of dozens of different tasks.

 

After a while, this implicates several problems that he wanted to solve.

 

The outcome of this principle is that you should not have a big interface that is in charge of creating all the things but segregate each task into different interfaces.

 

The following is a real-world example and we are going to see how to implements filters on a search page according to ISP.
 

interface Filter 
{
    public function buildQuery(
        Request $request;
        Query $query
    ) :query;
}


// other stuff here 

class Text implements Filter
{
    // construct here

    public function buildQuery(
        Request $request;
        Query $query
    )
    {
        if ($request->query($this->field)) {
            return $query->where(["{$this->table}.{$this->name} LIKE" 
                => "%" . $request->query($this->field) . "%"
            ]); 

        }

        return $query;
    }
}

 

The first and easier way to make this implementation is to have a Filter interface somewhere in your code that has a method that allows creating a query according to the request.

 

Then we implement this filter in our text field class check if the value of the parameter if set and then return the request the user wants.

 

Easy,

 

What will happen if the user of our application will look of the string “0”

 

You may know that PHP evaluates 0 as false, thus the code withing the if in our Text class will not execute and we just return the query as it is.

 

That’s a bug, Let’s fix it!
 

interface SearchParameters 
{
    public function has($parameter) :bool;

    public function value($parameter);
}



interface Filter 
{
    public function buildQuery(
       SearchParameters $parameters;
       Query $query
    ) :Query;
}

class StringSearchParameters implements searchParemeters 
{
    $private $request;

    public function __construct(Request $request) 
    {
        $this->request = $request;     
    }

    public function has(string $parameter) :bool
    {
        return $this->request->query($parameter) !== null
            && $this->request->query($parameter) !== "";
    }

    public function value(string $parameter)
    {
        if (!this->has($parameter)) {
            Throw new SearchParameterNotFound('No such parameter');
        }
        return $this->request->query($parameter);
    }
}

 

 

A way to fix this issue is to create a SearchParameters interface, it has two methods.

 

A has() method that returns a bool according to the result of the check we saw in the previous example and the value() method that return either the string of an Exception.

 

When it is time to perform our action we inject the request that will be saved by the constructor than evaluate the request with the has method and return the value accordingly.

 

Note that we have written much more code but the concept is that we write the code once and from now on this is now much easier to read.


if (!this->has($parameter))

 

That is basically plain English.

 

Now each interface has is own task, they are more loosely coupled.

 


Dependency inversion principle

 

Depend upon abstaction not concretions

 

To understand this we need to define what abstraction and concretions are,

 

Abstraction is a class that cannot be instantiated, basically abstract classes and interfaces.

 

An example is our Duck class before.

 

A concretion is the actual classes that we can retrieve an instance from WildDuck, RubberDuck, etc. 

 

I believe that if you already arrived at this point in the article without changing page you are familiar with dependency injection and constructor injection.

 

if not here is a quick explanation of dependency injection 

 

Well, dependency inversion states that you should invert the dependencies.

 

Invert the relationship in a way that, at first, may seem unnatural.

 

The goal of this principle is to increase the flexibility of our code. 

 

It’s doing so by exchanging one instance for another instance in order to change a particular behavior.

 

Let’s implement dependency inversion in one of our previous example
 

abstract class Duck {
    abstract public function swim();
}

class RubberDuck extends Duck{
    public function swim() 
    {
        return "I do not swim, I float";
    }
}


class WildDuck extends Duck{
    public function swim() 
    {
        return "I swim very fast";
    }
}

 

This is OOP 101, the code works just fine.

 

After all, these methods only return a string 

 

A year passed from the moment you deployed this code into production and now we need to we have way more types of swimming behaviour with more complex code.

 

According to the first 4 principles you have just discovered we could create different classes that are in charge of calculating the result for each type of duck.
 

abstract class SwimmingBehaviour {
    abstract public function swim();
}

class RubberDuckSwimmingBehaviour extends SwimmingBehaviour {
    public function swim() 
    {
        return "I do not swim, I float";
    }
}

class WildDuckSwimmingBehaviour extends SwimmingBehaviour {
    public function swim() 
    {
        return "I swim very fast";
    }
}

abstract class Duck {
    abstract public function swim();
}

class RubberDuck extends Duck{
    $this->behaviour = new RubberDuckSwimmingBehaviour;
    public function swim() 
    {
        return $this->behaviour->swim();
    }
}

class WildDuck extends Duck{
    $this->behaviour = new WildDuckSwimmingBehaviour;
    public function swim() 
    {
        return $this->behaviour->swim();
    }
}

 

Now, this code is a bit more complicated to understand.

 

Here we have two hierarchy, but it is easier to manage,  and we can add as much logic as we want in those behaviour classes.

 

Depend upon abstractions not concretions

 

Looking again at this priciple we recognize that something wrong is happening we are doing the exact opposite of what we should, the concrete duck classes are coupled with the low levels behaviors.

 

To solve this we need to invert the injections and as you will see we won’t need the low classes anymore.
 

abstract class SwimmingBehaviour {
    abstract public function swim();
}

class RubberDuckSwimmingBehaviour extends SwimmingBehaviour {
    public function swim() 
    {
        return "I do not swim, I float";
    }
}

class WildDuckSwimmingBehaviour extends SwimmingBehaviour {
    public function swim() 
    {
        return "I swim very fast";
    }
}

class Duck {
    Public function __construct(SwimmingBehaviour $behaviour)
    {
        $this->behaviour = $behaviour;
    }

    public function swim(){
        return $this->behaviour->swim();
    }
}

$wildDuck = new Duck(new WildDuckSwimmingBehaviour )
$wildDuck->swim(); // I swim very fast

 

Here we go,

 

We have fixed the code, we are complying with this solid principle and most important now our code is reliable long term.

 

The point of the Dependency inversion principle is that WE DO NOT NEED to instantiate subclasses in many cases dipendency injection is enough and we do not need hierarchies.

 

Plus our Duck class now cares only about the SwimmingBehaviour and does not know mind about the types WildDuckSwimmingBehaviour or RubberDuckSwimmingBehaviour.

 

Conclusion

 

We usually spend more time reading than writing code, so we should aim to optimize the readability of our code.

 

Smart programmers come up with theories every day but only a few sticks and still validate their conclusion after years.

 

The S.O.L.I.D. principles are one of them.

 

We have learned that we must keep our classes small and specialized so they will be easy to maintain, to extend and to refactor.

 

We should favor composition over inheritance.

 

We should use specific types and avoid to use an array when is not needed and especially throw anything on it.

 

We need to keep our coupling as loose as possible by creating dependency outiside a class and pass to our classes and use interfaces only when they are useful.

 

After this reading, I hope you implement these principles in your code and start considering yourself as a good programmer

 

This post was based on a talk made by Gareth Ellis at PHP UK Conference in 2017

 

You can thank him for his insight on twitter using @garethellis
 

 
 
If you like this content and you are hungry for some more join the Facebook's community in which we share info and news just like this one!

Other posts that might interest you

Coding (Php 7.x) Oct 11, 2019

How‌ ‌to‌ ‌become‌ the ‌best‌ ‌programmer‌ ‌in‌ ‌the‌ ‌world‌ (My journey)

See details
Coding (Php 7.x) Oct 28, 2019

How to design your software using UML diagrams [with case study]

See details
Coding (Php 7.x) Nov 4, 2019

Composition over Inheritance [example in PHP]

See details
Get my free books' review to improve your skill now!
I'll do myself