-
-
Notifications
You must be signed in to change notification settings - Fork 1
Feature Service subscribers
github-actions[bot] edited this page Jul 8, 2026
·
1 revision
Подписчик декларирует, какие сервисы ему нужны, и получает scoped-локатор с ленивым доступом только к ним — вместо всего контейнера. Аналог ServiceSubscriberInterface + ServiceLocator Symfony.
- Класс реализует
ServiceSubscriberInterface::getSubscribedServices(): array— карту «локальный ключ → id сервиса». - Конструктор принимает параметр типа
Psr\Container\ContainerInterface. - При autowiring контейнер подставляет туда не себя, а
ServiceSubscriberLocator, ограниченный этой картой. Доступ ленивый: сервис создаётся только приget($key).
use CloudCastle\DI\Contract\ServiceSubscriberInterface;
use Psr\Container\ContainerInterface;
final class ReportController implements ServiceSubscriberInterface
{
public function __construct(private readonly ContainerInterface $locator) {}
public static function getSubscribedServices(): array
{
return ['db' => Connection::class, 'pdf' => PdfRenderer::class];
}
public function export(): string
{
// Connection и PdfRenderer создаются лениво, только когда действительно нужны.
return $this->locator->get('pdf')->render($this->locator->get('db')->fetchAll());
}
}
$c = new Container();
$c->enableAutowiring();
$c->get(ReportController::class); // $locator — ServiceSubscriberLocator только с 'db' и 'pdf'-
Явный контракт зависимостей: видно, какие сервисы использует класс, прямо в
getSubscribedServices(). -
Лень без proxy: тяжёлые сервисы не создаются, пока не вызван
get($key)— полезно, когда из многих зависимостей в конкретном запросе нужна одна. - Инкапсуляция: класс получает не весь контейнер (service-locator антипаттерн во всю ширь), а узкий срез — только объявленное.
-
PSR-11: локатор реализует
Psr\Container\ContainerInterface— переносимо и тестируемо (легко подменить фейком).
- Это всё же локатор, а не чистая инъекция — доступ по строковому ключу, а не по типу; злоупотребление возвращает к service-locator антипаттерну.
- Ключи
getSubscribedServices()статичны и не проверяются на этапе autowiring (опечатка ключа всплывёт какNotFoundExceptionприget()). - Только для параметра
Psr\Container\ContainerInterface; полныйCloudCastle\DI\ContainerInterfaceпо-прежнему инъектирует весь контейнер.
- Контроллеры/обработчики с множеством редко используемых зависимостей — подписка + ленивый
get(). - Комбинировать с тегами: подписаться на конкретные сервисы, а не тянуть весь тег.
- Подписываться на десятки сервисов «на всякий случай» — это скрытая God-зависимость.
- Прокидывать локатор дальше по коду как универсальный контейнер — теряется весь смысл ограничения.
- Класть в
getSubscribedServices()ключи, которых нет в контейнере, и полагаться на них без обработкиNotFoundException.
| Контейнер | Аналог |
|---|---|
| PHP-DI | нет (❌ — только прямая инъекция) |
| Symfony |
ServiceSubscriberInterface + ServiceLocator (эталон) |
| Laravel | нет scoped-локатора подписки (❌) |
| Pimple | нет (❌) |
| Nette | нет (❌) |
CloudCastle, Symfony — декларативная подписка со scoped-локатором.
См. также: Теги и tagged services · Lazy service · Contextual binding.
CloudCastle DI · · PHP 8.1+ · PSR-11
GitHub · Packagist · Releases · Discussions · Сравнение
Исходники Wiki — каталог wiki/ в репозитории (синхронизация через GitHub Actions)
- 🏗️ Архитектура
- ⚡ Быстрый старт
- 📊 Сравнение — 5 аналогов, таблица + победители
- 🧩 Возможности (детально) — каждая фича: принцип, +/−, аналоги
- 🧪 Bootstrap
- 🚀 Compiled container
- 🔗 Contextual binding
- 🤖 Autowiring
- 📄 Конфигурация
- 📖 Справочник конфигурации
- 📂 Сканирование классов
- 🌍 Глобальный реестр
- 🏷️ Теги и декораторы
- 🔗 call(), bind(), hooks
- 🔄 Прототипы, alias, lazy, lazyGhost
- 📋 Справочник API
- 🏭 Фабрики и singleton