Solid principles in php
Posted on August 20th 2019In object-oriented computer programming, SOLID is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable.
S.O.L.I.D. STANDS FOR:
S — Single responsibility principle.
O — Open closed principle.
L — Liskov substitution principle.
I — Interface segregation principle.
D — Dependency Inversion principle.
S — Single responsibility principle
In programming, the Single Responsibility Principle states that every module or class should have responsibility over a single part of the functionality provided by the software. You may have heard the quote:
“Do one thing and do it well”.
This refers to the single responsibility principle.
In the article Principles of Object Oriented Design, Robert C. Martin
defines a responsibility as a ‘reason to change’, and concludes that a class or module should have one, and only one, reason to be changed.
<?php
class Logger
{
private $logs = [];
public function add($log)
{
$now = new DateTime();
$date = $now->format("Y-m-d h:i:s.u");
$this->logs[] = $date . " : " . $log;
}
public function toString($dimiliter = ", ")
{
if (empty($this->logs)) {
return "No logs";
}
return implode($this->logs, $dimiliter);
}
public function reset()
{
$this->logger = [];
}
public function save($fileName)
{
$fp = fopen($fileName, "w");
fwrite($fp, $this->toString("\n"));
fclose($fp);
}
}
class LogStorage
{
private $fileName;
public function __construct($fileName)
{
$this->fileName = $fileName;
}
public function save($text)
{
$fp = fopen($this->fileName, "w");
fwrite($fp, $text);
fclose($fp);
}
}
$logger = new Logger();
$logger->add("First log");
$logger->add("Second log");
$logger->add("Third log");
$logStorage = new LogStorage(dirname(__FILE__) . "/logs.txt");
$logStorage->save($logger->toString("\n"));
O — Open/closed principle
This principal purpose that existed and well-tested class should not be modified when a new feature needs to be built. It may introduce a new bug when we modify an existing class to make a new feature. So rather than changing an existing class/Interface, we should extend that class/Interface in a new class to add new features. “Software entities … should be open for extension, but closed for modification.” If you have a general understanding of OOP, you probably already know about polymorphism. We can make sure that our code is compliant with the open/closed principle by utilizing inheritance and/or implementing interfaces that enable classes to polymorphically substitute for each other.
Let’s understand with the example:
<?php
interface Account
{
public function calculateInterest();
}
class SavingAccount implements Account
{
private $balance;
private $rate = 3.0;
private $maturityPeriod;
public function setBalance($balance)
{
}
public function getBalance()
{
}
public function withdrawal()
{
}
public function calculateIntrest()
{
$this->{$rate} * $this->balance;
}
}
class FixedDipositAccount implements Account
{
private $balance;
private $rate = 9.5;
public function setBalance($balance)
{
}
public function getBalance()
{
}
public function calculateIntrest()
{
$this->{$rate} * $this->balance;
}
}
class IntrestCalculator
{
public function calculate(Account $account)
{
return $account->calculateIntrest();
}
}
$savingAccount = new SavingAccount();
$savingAccount->setBalance(15000);
$fdAccount = new FixedDipositAccount();
$fdAccount->setBalance(25000);
$intrestCalculator = new IntrestCalculator();
echo $intrestCalculator->calculate($savingAccount);
echo $intrestCalculator->calculate($fdAccount);
L — Liskov substitution principle
This principle is named after the name of Barbara Liskov. She introduced this principle in 1987. The concept states that a subtype must be substitutable to base types without breaking the behavior. It is a particular definition of subtyping relation, called behavioral subtyping.
TL;DR
Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
This one is probably the hardest one to wrap your head around when being introduced for the first time.
In programming, the Liskov substitution principle states that if S is a subtype of T, then objects of type T may be replaced (or substituted) with objects of type S.
This can be formulated mathematically as
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.
More generally it states that objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
The following are the conditions to avoid LSP violation.
Method signatures must match and accept equal no of the parameter as the base type
The return type of the method should match to a base type
Exception types must match to a base class
I — Interface segregation principle
This principle is fairly easy to comprehend. In fact, if you’re used to using interfaces, chances are that you’re already applying this principle.
If not, it’s time to start doing it! In programming, the interface segregation principle states that no client should be forced to depend on methods it does not use. Put more simply: Do not add additional functionality to an existing interface by adding new methods.
Instead, create a new interface and let your class implement multiple interfaces if needed.
D - Dependency inversion principle
Finally, we got to D
, the last of the 5 principles.
In programming, the dependency inversion principle is a way to decouple software modules.
This principle states that High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
To comply with this principle, we need to use a design pattern known as a dependency inversion pattern, most often solved by using dependency injection. Dependency injection is a huge topic and can be as complicated or simple as one might see the need for. Typically, dependency injection is used simply by ‘injecting’ any dependencies of a class through the class’ constructor as an input parameter.