Три схожі назви - три різні речі:
Dependency Injection (впровадження залежностей) - техніка: об'єкт отримує залежності ззовні (через конструктор), а не створює їх сам.
// Без DI
class ReportService { private $mailer; public function __construct() { $this->mailer = new SmtpMailer(); } }
// З DI
class ReportService { public function __construct(private Mailer $mailer) {} }
Dependency Inversion Principle (DIP, «D» у SOLID) - принцип проєктування:
- Модулі високого рівня (бізнес-логіка) не мають залежати від модулів низького рівня (база, пошта, HTTP). Обидва залежать від абстракцій.
- Абстракції не залежать від деталей - деталі залежать від абстракцій.
«Інверсія» в тому, що інтерфейс належить бізнес-логіці й описаний її мовою, а інфраструктура його реалізує. Не «у нас є Stripe, давайте загорнемо його API в інтерфейс», а «бізнес-логіці потрібно PaymentGateway::charge(), а Stripe - одна з реалізацій».
IoC-контейнер (Service Container у Laravel) - інструмент, який автоматизує DI: сам створює об'єкти й підставляє залежності.
Зв'язок: DI можна робити без DIP - впроваджувати конкретний клас StripeClient. Тоді залежність ззовні, але бізнес-логіка все одно прив'язана до деталі. DIP додає абстракцію, а DI - спосіб її доставити.
Коли DIP виправданий: межі з зовнішнім світом, які справді можуть змінитися чи які треба підміняти в тестах - платежі, пошта, сторонні API, сховища. Інтерфейс на кожен клас «про всяк випадок» лише додає файлів і непрямих викликів без користі.