Definicje klas i interfejsów
Przyjmijmy następujące definicje klas:
<?php
interface ShapeContract
{
public float $area { get; }
}
interface CalculatorContract
{
public function calculate(): float;
}
interface TextContract
{
public function text(): string;
}
interface JsonContract
{
public function json(): string;
}
class Square implements ShapeContract
{
public function __construct(private readonly int $length){}
public float $area {
get => $this->length * $this->length;
}
}
class Circle implements ShapeContract
{
public function __construct(private readonly int $radius){}
public float $area {
get => $this->radius * $this->radius * pi();
}
}
readonly class AreaCalculator implements CalculatorContract
{
/**
* @param array $shapes
*/
public function __construct(protected array $shapes)
{
}
public function calculate(): float
{
$data = array_map(fn(ShapeContract $shape) =>
$shape->area, $this->shapes);
return array_sum($data);
}
}
readonly class BigAreaCalculator extends AreaCalculator
{
public function calculate(): float
{
$initial = parent::calculate();
//some additional logic and filters like not less than
return $initial;
}
}
readonly class SumCalculatorOutputter implements TextContract, JsonContract
{
public function __construct(private CalculatorContract $calculator){}
public function text(): string
{
return "The sum of the areas of the shapes is: " . $this->calculator->calculate();
}
public function json(): string
{
return json_encode(['sum' => $this->calculator->calculate()]);
}
}
Zasada jednej odpowiedzialności - SRP
Klasa powinna mie¢ tylko jedn¡ odpowiedzialno±¢. Jedyne co potrafią klasy Square i Square to policzenie swojego pola. Zadaniem klasy AreaCalculator jest wyliczenie pola dla tablicy figur i bez znaczenia jest tutaj, w jaki sposób ka»da z figur liczy swoje pole. Natomiast jedynym zadaniem klasy SumCalculatorOutputter jest wyświetlenie wyniku jako tekst lub json.
Zasada otwarte-zamknięte - OCP
Klasy powinny by¢ otwarte na rozszerzenia i zamkni¦te na modyfikacje. Ponieważ klasy Square i Circle uzywają interfejsu do obliczenia swojego pola, dodanie nowej klasy (np trójkąta) nie wymaga od nas modyfikacji klasy kalkulatora. Dodatkowo użycie array_map gwarantuje, że wszystkie obiekty będą miały zaimplementowany getter dla pola $area.
Zasada podstawienia Liskova - LSP
Funkcje które używają wskaźników lub referencji do klas bazowych, muszą być w stanie używać również obiektów klas dziedziczących po klasach bazowych, bez dokładnej znajomości tych obiektów. Klasa BigAreaCalculator spełnia tą zasadę ponieważ nie ma większego znaczenia co dokładnie robi klasa bazowa
Zasada segregacji interfejsów - ISP
Wiele dedykowanych interfejsów jest lepsze niż jeden ogólny. Klasa SumCalculatorOutputter spełnia tą zasad¦, poniewż za ka»dy z rodzajów zwracanego wyjścia odpowiada dedykowany interfejs.
Zasada odwrócenia zależności - DIP
Wysokopoziomowe moduły nie powinny zależe¢ od modułów niskopoziomowych - zale»no±ci między nimi powinny wynikać z abstrakcji. Każdy z modułów spełnia tą zasadę. Kalkulatory w konstruktorze przyjmują interfejs dla kształtu, natomiast klasa do wyświetlania wyników przyjmuje w konstruktorze interfejs kalkulatora. Należy dodatkowo zwrócić uwagę, że wszystkie klasy otrzymują swoje zależności już w konstruktorze. Przykładem zastosowania może być kontener zależności
Zamów praktyczny kurs PHP już teraz!
Dowiedz się jak działają współczesne frameworki PHP

Kup teraz 149 zł
Nasz kurs PHP w praktyce to inwestycja w Twoją karierę. Po zakupie zyskasz:
Pełny dostęp do materiałów kursu
Możliwość czytania e-booka online
Przeglądarkę kodu źródłowego z praktycznymi przykładami
Możliwość pobrania w formatach PDF/EPUB/Markdown