1.1 Les principes SOLID
S - Single Responsibility Principle (SRP)
Définition : Une classe ne doit avoir qu'une seule raison de changer.
Mauvais exemple :
class OrderService
{
public function createOrder(array $data): Order { /* ... */ }
public function sendConfirmationEmail(Order $order): void { /* ... */ }
public function generateInvoicePdf(Order $order): string { /* ... */ }
public function updateStock(Order $order): void { /* ... */ }
}
Bon exemple :
class OrderService
{
public function __construct(
private OrderRepository $orderRepository,
private StockManager $stockManager,
private EventDispatcherInterface $dispatcher
) {}
public function createOrder(array $data): Order
{
$order = new Order($data);
$this->orderRepository->save($order);
$this->stockManager->decreaseStock($order);
$this->dispatcher->dispatch(new OrderCreatedEvent($order));
return $order;
}
}
O - Open/Closed Principle (OCP)
Définition : Ouvert à l'extension, fermé à la modification.
Bon exemple avec Strategy Pattern :
interface DiscountStrategyInterface
{
public function supports(string $type): bool;
public function calculate(Order $order): float;
}
class DiscountCalculator
{
public function __construct(
/** @var iterable<DiscountStrategyInterface> */
private iterable $strategies
) {}
public function calculate(Order $order, string $type): float
{
foreach ($this->strategies as $strategy) {
if ($strategy->supports($type)) {
return $strategy->calculate($order);
}
}
throw new UnsupportedDiscountException($type);
}
}
L - Liskov Substitution Principle (LSP)
Définition : Une classe dérivée doit pouvoir remplacer sa classe parente sans casser le comportement.
Bon exemple :
interface ShapeInterface
{
public function getArea(): int;
}
class Rectangle implements ShapeInterface
{
public function __construct(private int $width, private int $height) {}
public function getArea(): int { return $this->width * $this->height; }
}
class Square implements ShapeInterface
{
public function __construct(private int $side) {}
public function getArea(): int { return $this->side ** 2; }
}
I - Interface Segregation Principle (ISP)
Définition : Plusieurs interfaces spécifiques valent mieux qu'une interface générale.
interface ProductInterface
{
public function getName(): string;
public function getPrice(): float;
}
interface PhysicalProductInterface extends ProductInterface
{
public function getWeight(): float;
public function getStock(): int;
}
interface DigitalProductInterface extends ProductInterface
{
public function getDownloadUrl(): string;
}
D - Dependency Inversion Principle (DIP)
Définition : Dépendre des abstractions, pas des implémentations concrètes.
interface OrderRepositoryInterface
{
public function save(Order $order): void;
public function findById(int $id): ?Order;
}
class OrderService
{
public function __construct(
private OrderRepositoryInterface $repository // Abstraction injectée
) {}
}