PHP Course : SOLID - Liskov Substitution
Third principle in this SOLID serie, the Liskov Substitution principle was imagined by Barbara Liskov.
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.
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.
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.
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.
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 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.
How not to break the Liskov Substitution Principle:
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.
I consider myself as an IT Business Artisan. Or Consultant CTO. I'm a self-taught Web Developper, coach and teacher. My main work is helping and guiding digital startups.
more about meBTC
18SY81ejLGFuJ9KMWQu5zPrDGuR5rDiauM
ETH
0x519e0eaa9bc83018bb306880548b79fc0794cd08
XMR
895bSneY4eoZjsr2hN2CAALkUrMExHEV5Pbg8TJb6ejnMLN7js1gLAXQySqbSbfzjWHQpQhQpvFtojbkdZQZmM9qCFz7BXU
2024 © My Dynamic Production SRL All rights Reserved.