PHP Course : SOLID - Liskov Substitution

PHP Course : SOLID - Liskov Substitution


Feb 11 2019, 13:07 in Web Development

Third principle in this SOLID serie, the Liskov Substitution principle was imagined by Barbara Liskov.

Definition

Mathematical definition:

Let q(x) be a property provable about object x of type T.

Then q(y) should be provable for objects y of type S where S is a subtype of T.

Official definition

This principle states that any implementation of an abstraction (interface) should be substitutable in any place that the abstraction is accepted.

What the hell does that mean ? Well you'll see that it's almost the same thing repeated over and over accross principles.

Monkey definition

Derived classes must be substituable for their base class.

Every time you prepare a subclass, that subclass should be substituable in every place where the original class was accepted.

Any implementation of an abstraction or an interface should be substitutable anywhere that the abstraction is accepted.

Examples

Basic Example

Let's imagine the most basic code

class A
{
    public function execute() {}
}

class B extends A
{
}

The principle dictates that, everywhere you use A, you should be able to use B instead, without breaking anything.

Yes, it seems like common sense, right ? Let's view another example where things could break.

LSP Violation Example

class Animal
{
    public function fly()
    {
    }
}

class Dog extends Animal
{
    public function fly()
    {
        if (! $this->hasWings) {
            throw new Exception; // violates Liskov Substitution Principle
        }
    }
}

Based on this example, if your code use the Animal class to fly(), because your program handles birds, and that you substitute Animal with Dog (which is an animal, but can't fly) then the output of your code will change. This violates the Liskov Substitution Principle.

What we demonstrated here is an illustration of the pre conditions being too great. But that's not the only thing you need to worry about!

If you remember the Single Responsability Principle and the Open Closed Principle, you should remember that you need to code through contracts.

Interface Example

interface ArticleRepositoryInterface
{
    public function getAll();
}

class MarkdownFileArticleRepository implements ArticleRepositoryInterface
{
    public function getAll()
    {
        // grab all .md files on disk
        return [];
    }
}

class DatabaseArticleRepository implements ArticleRepositoryInterface
{
    public function getAll()
    {
        return Article::all(); // violates LSP because returns a collection
    }
}

In this example we still violates the Liskov Substitution Principle because the output of the getAll() methods are different. The first one returns an array while the second one returns an Eloquent Collection.

That means that the consumer of those repositories will not be able to interract in the same way with the output if we substitute one repository with the other. This simple fact violates the LSP.

Conclusion

How not to break the Liskov Substitution Principle:

  • Signatures must match the Interface (return typing)
  • Preconditions can't be greater (Dog can't fly example)
  • Post conditions at least equal to
  • Exception types must match.

In other word, use interface to make sure you can substitute a class with another, and also use return types to make sur you can still interact with the output without any break.


Share:
Like:

Disable AdBlock on this domain and offer me a cup of coffee :)