Ähnlich wie “SOLID principles in PHP – how to apply them in PHP and why should we care“ by Jānis Mozgis from Printful Latvia at Modern PHP focused 66th DevClub.lv
Ähnlich wie “SOLID principles in PHP – how to apply them in PHP and why should we care“ by Jānis Mozgis from Printful Latvia at Modern PHP focused 66th DevClub.lv (20)
8. Open-Closed
class Order {
public function calculateTotal() {
foreach ($this->products as $product) {
$this->total += $prouct->calculatePrice() + $product->calculateShipping();
}
}
public function addProduct(Product $product) {
$this->products[] = $product;
}
}
class Product {
public function calculatePrice() { // … }
public function calculateShipping() { // … }
}
9. Open-Closed
class Order
{
public function calculateTotal() {
foreach ($this->products as $product) {
if ($procut->type == 'digital') {
$this->total += $prouct->calculatePrice();
} else {
$this->total += $prouct->calculatePrice() + $product->calculateShipping();
}
}
}
}
10. Open-Closed
class Order
{
public function calculateTotal() {
foreach ($this->products as $product) {
if ($procut->type == 'digital') {
$this->total += $prouct->calculatePrice();
} elseif ($procut->type == 'sample') {
$this->total += $prouct->calculateShipping();
} else {
$this->total += $prouct->calculatePrice() + $product->calculateShipping();
}
}
}
}
11. Open-Closed
class Order {
public function calculateTotal() {
foreach ($this->products as $product) {
$total += $product->calculateTotal();
}
}
public function addProduct(ProductPriceCalculation $product) {
$this->products[] = $product;
}
}
interface ProductPriceCalculation {
public function calculateTotal(): float;
}
12. Open-Closed
class DiditalProduct implements ProductPriceCalculation
{
public function calculateTotal(): float
{
return $this->calculatePrice();
}
}
class SamplelProduct implements ProductPriceCalculation
{
public function calculateTotal(): float
{
return $this->calculateShipping();
}
}
13. Open-Closed
class NormalProduct implements ProductPriceCalculation
{
public function calculateTotal(): float
{
return $this->calculateShipping() + $this->calculatePrice();
}
}
14. Liskov Substitution
“Let q(x) be a property provable about objects of x of type T. Then
q(y) should be provable for objects y of type S where S is a subtype
of T..”
16. Liskov Substitution
class Rectangle
{
protected $width;
protected $height;
public function setHeight($height) { $this->height = $height; }
public function getHeight() { return $this->height; }
public function setWidth($width) { $this->width = $width; }
public function getWidth() { return $this->width; }
public function area() { return $this->height * $this->width; }
}
17. Liskov Substitution
class Square extends Rectangle
{
public function setHeight($value) {
$this->width = $value;
$this->height = $value;
}
public function setWidth($value) {
$this->width = $value;
$this->height = $value;
}
}
18. Liskov Substitution
class RectangleTest
{
private $rectangle;
public function __construct(Rectangle $rectangle)
{
$this->rectangle = $rectangle;
}
public function testArea()
{
$this->rectangle->setHeight(2);
$this->rectangle->setWidth(3);
// Expect rectangle's area to be 6
}
}
19. Interface Segregation
“A client should never be forced to implement an interface that it
doesn't use or clients shouldn't be forced to depend on methods
they do not use.”
20. Interface Segregation
interface ShapeInterface {
public function calculateArea(): float;
public function calculateVolume(): float;
}
Class Cube implements ShapeInterface {
$this->height;
public function calculateArea() { return pow($this->height, 2); }
public function calculateVolume() { return pow($this->height, 3); }
}
class Square implements ShapeInterface {
$this->height;
public function calculateArea() { return pow($this->height, 2); }
public function calculateVolume() { /* do nothing? */ }
}
22. Interface Segregation
class Cube implements AreaCalculationInterface, VolumeCalculationInterface
{
$this->height;
public function calculateArea() { return pow($this->height, 2); }
public function calculateVolume() { return pow($this->height, 3); }
}
class Square implements AreaCalculationInterface
{
$this->height;
public function calculateArea() { return pow($this->height, 2); }
}
23. Dependency Inversion
“Entities must depend on abstractions not on concretions.
High level module must not depend on the low level module, but
they should depend on abstractions.”
”
24. Dependency Inversion
class PasswordReminder {
private $dbConnection;
public function __construct(MySQLConnection $dbConnection) {
$this->dbConnection = $dbConnection;
// send out reminder logic
}
}
25. Dependency Inversion
interface DBConnectionInterface {
public function connect();
}
class MySQLConnection implements DBConnectionInterface {
public function connect() {
// connection logic
}
}
class PasswordReminder {
private $dbConnection;
public function __construct(DBConnectionInterface $dbConnection) {
$this->dbConnection = $dbConnection;
// send out reminder logic
}
}
26. SOLID - pros and cons
Pros:
● Izmaiņas kādā applikācijas daļā nesalauzīs
citu daļu;
● Kods ir fleksiblāks koda izmaiņām;
● Applikācijas daļas ir vieglāk testējamas;
Cons
● Jāraksta nedaudz vairāk koda
● Applikācija var izaugt daudz mazos moduļos
līdz ar to ir grūtāk orientēties;
● Reālā dzīvē bieži ir grūti paredzēt, kur
izmantot šos principus un kur nē.
Principus pirmais aprasktija Robert C. Martin 90to beigās, Uncle Bob
Galīgi nav piesieti PHP, bet der jebkurai OO valodai
Galenais mērķis ir padarīt koda lasāmību un paplašināmību vienkāršāku.
Rezultātā padara kodu mazāk sasaistītu un atkarīgu no citām daļām
Samazina iespējamo bugu rašanos
Padara vienkāršāku testēšanu.
Tas nav “sasniedzams rezultāts”, bet mērķis, uz kuru tiekties
Manuprāt VIens no grūtākajiem principiem, jo tas prasa iepriekšēju domāšanu par klašu struktūru
Var radikāli mainīt uzturēšanas sarežģītību
Baigi daudz kas notiek vienā kontrolierī
Kontrolierim nevajadzētu izpildīt biznesa loģiku
Loģika tiek iznesta ārā no kontroliera
Šai klasei tagad ir jāmainās tikai tad, ja
Tas nav īsti PHP klašu inheritance dēļ “exted” keyword…
Open - būtu jābūt vienkārši mainīt to, ko klase dara
Closed - to, ko klase dara būtu jāvar viegli mainīt, nemoanot pašu klases kodu
Viss izskatās skaisti, bet pēķšņi ir jāpieliek digitāli produkti, kam nav vajadzīgs shipping
Ieleikam loģiku Order klasē? Bet ja nu būs jāliek vēl kāds produktu tips, piemēram sample produkt, kam nav price, bet ir tikai shipping?
Ieleikam loģiku Order klasē? Bet ja nu būs jāliek vēl kāds produktu tips, piemēram sample produkt, kam nav price, bet ir tikai shipping?
Izveidojam interfeisu, kas definēs, ka ir jārēķina cena
Pie produkta pievienošanas typehintingā izmantojam interfeisu, nevis klasi
Cenas rēķināsanu atstājam katrai klasei
Rolls of the tongue nicely….
Autore ir Barbara Liskov
Iet roku rokā ar “code to a interface” vai “design by contract”
Ja child class parraksta parent class loģiku, tad tā nedrīkst salauzt parent class loģiku
Typehinting atļaus izmantot square klases inastances, bet tests feilos
Tas nav tas pats, kas depedency injections
Bet tas ir vajadzīgs, lai dependency inversion strādātu
Šis princips atļauj mums efektīvāk rakstīt de-coupled kodu