PSR-11 - мінімальний спільний інтерфейс контейнера залежностей. Усього два методи:
namespace Psr\Container;
interface ContainerInterface
{
public function get(string $id); // отримати запис або кинути NotFoundExceptionInterface
public function has(string $id): bool;
}
Навіщо такий мінімалізм: стандарт описує лише отримання сервісів, а не їхню реєстрацію. Конфігурація (прив'язки, автовпровадження, синглтони) у кожного контейнера своя, а споживання - однакове.
Що це дало екосистемі:
- Фреймворко-незалежні бібліотеки й фреймворки. Slim, Mezzio, роутери й диспетчери middleware приймають будь-який PSR-11-контейнер: PHP-DI, Symfony DependencyInjection, League Container, Laravel.
- Laravel реалізує PSR-11:
Illuminate\Container\Container- цеContainerInterface, тож сторонні бібліотеки, що очікують PSR-контейнер, працюють з ним. - Композиція контейнерів - делегування пошуку іншому контейнеру.
Застереження - Service Locator. PSR-11 прямо не радить передавати контейнер у бізнес-класи, щоб вони самі діставали залежності:
// Погано: прихована залежність, важко тестувати
final class ReportService
{
public function __construct(private ContainerInterface $container) {}
public function build(): void
{
$mailer = $this->container->get(Mailer::class);
}
}
// Добре: залежність явна
final class ReportService
{
public function __construct(private Mailer $mailer) {}
}
Контейнер - для «склеювання» застосунку на верхньому рівні (фабрики, фреймворк), а не для використання всередині логіки. Виняток - фабрики, що за природою створюють різні об'єкти за ідентифікатором.