Pięć zasad SOLID w PHP
Zasady SOLID to zbór najlepszych praktyk programowania obiektowego, które pomagają w tworzeniu kodu elastycznego, łatwego do utrzymania i rozbudowy. Oto ich omówienie wraz z przykładami w PHP.
1. Single Responsibility Principle (SRP) - Zasada pojedynczej odpowiedzialności
Każda klasa powinna mieć tylko jeden powód do zmiany, czyli powinna zajmować się jedną konkretną funkcjonalnością.
Przykład poprawny:
class ReportGenerator {
public function generate(array $data): string {
return json_encode($data);
}
}
class FileSaver {
public function saveToFile(string $content, string $filename): void {
file_put_contents($filename, $content);
}
}
Tutaj ReportGenerator
generuje raport, a FileSaver
go zapisuje. Każda klasa ma pojedynczą odpowiedzialność.
Kiedy można złamać SRP?
Jeśli rozbicie odpowiedzialności na wiele klas nadmiernie komplikuje kod i powoduje problemy z zarządzaniem zależnościami, np. w bardzo małych projektach.
2. Open/Closed Principle (OCP) - Zasada otwarte-zamknięte
Klasa powinna być otwarta na rozbudowę, ale zamknięta na modyfikacje.
Przykład poprawny:
interface PaymentMethod {
public function pay(float $amount);
}
class CreditCardPayment implements PaymentMethod {
public function pay(float $amount) {
echo "Paid $amount using Credit Card.";
}
}
class PayPalPayment implements PaymentMethod {
public function pay(float $amount) {
echo "Paid $amount using PayPal.";
}
}
Dzięki zastosowaniu interfejsu możemy dodać nową metodę płatności bez zmieniania istniejącego kodu.
Kiedy można złamać OCP?
Gdy przewidywanie przyszłych zmian jest niemożliwe i potrzeba szybkich poprawek w kodzie.
3. Liskov Substitution Principle (LSP) - Zasada podstawiania Liskov
Obiekty podklas powinny mogą być używane w miejsce obiektów klas bazowych bez zmiany poprawności programu.
Przykład poprawny:
class Bird {
public function fly() {
echo "I am flying";
}
}
class Sparrow extends Bird {}
Sparrow
może latać, więc zasada LSP jest zachowana.
Przykład błędny:
class Penguin extends Bird {
public function fly() {
throw new Exception("I can't fly!");
}
}
Penguin
nie powinien dziedziczyć po Bird
, ponieważ narusza oczekiwania dotyczące klasy nadrzędnej.
Kiedy można złamać LSP?
Jeśli korzyści z ponownego użycia kodu przewyższają ryzyko wprowadzenia nieoczekiwanych błędów.
4. Interface Segregation Principle (ISP) - Zasada segregacji interfejsów
Klasy nie powinny być zmuszane do implementowania metod, których nie potrzebują.
Przykład poprawny:
interface Printer {
public function printDocument();
}
interface Scanner {
public function scanDocument();
}
class MultiFunctionPrinter implements Printer, Scanner {
public function printDocument() {
echo "Printing document...";
}
public function scanDocument() {
echo "Scanning document...";
}
}
Dzięki podziale interfejsów, klasy implementują tylko te metody, które są im potrzebne.
Kiedy można złamać ISP?
Gdy podział interfejsów prowadzi do zbyt dużej fragmentacji i utrudnia zarządzanie kodem.
5. Dependency Inversion Principle (DIP) - Zasada odwrócenia zależności
Klasy wyższego poziomu nie powinny zależeć od klas niższego poziomu. Obie powinny zależeć od abstrakcji.
Przykład poprawny:
interface Logger {
public function log(string $message);
}
class FileLogger implements Logger {
public function log(string $message) {
file_put_contents('log.txt', $message, FILE_APPEND);
}
}
class UserService {
private Logger $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function registerUser(string $username) {
$this->logger->log("User $username registered");
}
}
Dzięki zastosowaniu interfejsu Logger
, możemy łatwo zmienić sposób logowania.
Kiedy można złamać DIP?
Gdy zależności są statyczne i nie przewidujemy potrzeby ich zmiany.
Podsumowanie
Zasady SOLID pomagają w tworzeniu kodu elastycznego i łatwego do rozbudowy. Ich stosowanie jest szczególnie ważne w dużych projektach, ale w małych można je czasem świadomie łamać, aby uniknąć zbędnej komplikacji.