> Записи `context`/`config`/`settings`/`servers`/`bouquets`/`categories` представляют собой простые данные
> снимки, сделанные при загрузке, а не на ленивых заводах — они считываются, а не пересчитываются, на протяжении всего срока службы устройства.
> запрос.
---
## Ссылка на сервисный контейнер
Все установщики могут быть объединены в цепочку (`return $this`).
|Метод|Цель|
| --- | --- |
| `set(id, value)` |Зарегистрируйте сервис. Значение **`Closure`** становится **ленивая фабрика синглетов** (сначала вызывается один раз для `get()`, затем кэшируется); все остальное — скаляр, объект или массив `[Class, 'method']` — сохраняется как готовое значение.|
| `factory(id, callable)` |Зарегистрируйте фабрику, которая возвращает значение **новый экземпляр для каждого `get()`** (без кэширования).|
| `register(array)` |Скопируйте `set()`с карты `id => value`.|
| `get(id)` |Разрешить службу. Возвращает кэшированный синглтон, если он присутствует; в противном случае запускает фабрику один раз, кэширует ее и применяет декораторы. Защищает от циклических фабрик и выдает `CircularDependencyException`; выдает `NotFoundException` для неизвестного идентификатора.|
| `getOrDefault(id, default)` |Как `get()`, но возвращает `default` вместо того, чтобы выбрасывать при отсутствии.|
|`has(id)` / `keys()` / `remove(id)` / `dump()`|Самоанализ и разрушение.|
| `decorate(id, decorator, priority)` |Завершите работу с существующей службой, наивысший приоритет которой был применен последним. **Запрещенный** в защищенных службах `['db', 'settings', 'config', 'auth']` — выберите один из вариантов оформления. Смотрите [Пункты расширения модуля](module-extension-points.md).|
|`tag(id, tag)` / `getTagged(tag)`|Сгруппируйте службы под одной меткой для пакетного поиска.|
> **Метки в настоящее время не используются основной проводкой.** `tag()`/`getTagged()` существует, но путь загрузки
> собирает вклады модулей путем проверки `instanceof` по списку загруженных модулей (см.
> [`bootAll`](#moduleloaderbootall-the-orchestrator)), **нет** по тегу. Исходный документированный блок все еще
> описывает теги как механизм сбора данных для подписчиков/cron/маршрутов, который описывает
> предполагаемый дизайн, а не текущий код. Не полагайтесь на коллекцию на основе тегов, пока она не будет создана на самом деле.
> реализованный.
Resolving a `[Class, 'method']` handler (used by the Router) goes **through the container**, so
классы-обработчики разграничиваются при регистрации, а в противном случае возвращаются к `new`.
---
## `ModuleLoader::bootAll` — организатор
После того, как `ModuleLoader::loadAll()` обнаружил, отфильтровал и **топологически отсортированный** отобрал модули
(see [Module Lifecycle](module-lifecycle.md)), `bootAll()` is the single place that pushes each
вклад модуля в основные реестры. Он проверяет каждое значение **подинтерфейс** на `instanceof`
таким образом, модуль реализует только те перехватчики, которые ему нужны (`ModuleInterface` - это их совокупность).
Порядок для каждого модуля внутри `bootAll(ServiceContainer $container, ?Router $router, ?StreamPipeline $pipeline)`:
1.**Сначала основная навигационная панель, один раз** — `(new CoreNavbarProvider())->registerNavbar(...)` перед любым модулем, поэтому узлы основного меню существуют как родительские.
2.`ServiceProviderInterface` → `boot($container)`**затем**`registerEventSubscribers()` — службы регистрируются до подключения слушателей этого модуля.
3.`StreamMiddlewareProviderInterface` → `registerStreamMiddleware($pipeline)` — **только в том случае, если было передано значение `$pipeline`**.
4.`RouteProviderInterface` → `registerRoutes($router)` — **только в том случае, если было передано значение `$router`** (`$router !== null`).
Два вклада равны **отдельные проходы, не являющиеся частью `bootAll`**:
-`registerAllCommands($registry)` — Команды CLI, каждый модуль которых заключен в try / catch, поэтому один сломанный модуль не может заблокировать весь CLI.
-`collectCronEntries()` — строки crontab, собранные из `CronProviderInterface::getCronEntries()`, используемые командами запуска/состояния.
Потому что маршруты и потоковое промежуточное программное обеспечение стробируются на основе необязательных аргументов `$router`/`$pipeline`,
**одно и то же значение `bootAll()` выполняет различную работу в зависимости от точки входа** — интерфейс командной строки не передает ни,
таким образом, к нему подключены только подписчики services + event (и безвредная навигационная панель).
---
## События
`EventDispatcher` (`src/Core/Events/EventDispatcher.php`) - это синглтон со статическим фасадом.
`populateContainer()` выполняет `new EventDispatcher()` → `EventDispatcher::setInstance($d)` →
`$container->set('events', $d)`, таким образом, запись контейнера `events` и статический
`EventDispatcher::dispatch()/listen()` общий доступ к хранилищу прослушивателей **один**. Модули регистрируют прослушиватели
во время шага 2 из `bootAll`, описанного выше, с помощью атрибута `getEventSubscribers()` или `#[ListensTo]`.
Полная информация - регистрационные формы, приоритеты, мероприятия, которые можно отменить, встроенный каталог мероприятий — приведена ниже.
в [системе событий](event-system.md); на этой странице описывается только *где в последовательности загрузки* прослушиватели
1.**Автоматическое обнаружение ядра.**`new CommandRegistry()`, затем глобус `Cli/Commands/*.php` и
`Cli/CronJobs/*.php`, сопоставьте каждый каталог с его пространством имен и с помощью отражения `register()` каждый
**неабстрактный** класс, реализующий `CommandInterface`. Таким образом, добавление основной команды - это просто
удаление класса в одном из этих каталогов — никакой ручной регистрации.
2.**Команды модуля.**`ModuleLoader::registerAllCommands($registry)` вызывает каждый
`CommandProviderInterface::registerCommands()`.
`CommandRegistry` (`src/Cli/CommandRegistry.php`) - это простая карта `name → CommandInterface`:
`register()`, `dispatch($argv)` (обрабатывает `--list`/`--help`, группирует справку по префиксу `group:` в
название команды), `get($name)`, `getAll()`.
---
## Сквозная загрузка — администрирование (web)
`src/Public/index.php`:
1.`XC_Bootstrap::boot(BootContext::Admin)` — создает контейнер; устанавливает `context`/`options`/`config`; загружает константы; выполняет проверку флуда/хостинга; `bootAdmin()` (сессия, база данных, `LegacyInitializer`, Redis, API администратора/реселлера, транслятор, обработчик завершения работы, константы состояния); **`populateContainer()`**; **`assertContainerHealth()`**.
2.`Router::getInstance()`, затем `require` основные файлы маршрутов `routes/{scope}.php` (+ `routes/api.php`).
3. Блок загрузки модуля: `router->beginModuleRegistration()` → `new ModuleLoader; loadAll(); bootAll($container, $router)` → `router->endModuleRegistration()` → `drainRouteCollisions()`. Режим регистрации модуля выполняет **выигрывают основные маршруты** по любому маршруту модуля с одинаковым путем; коллизии фиксируются, а не перезаписываются автоматически.
Смотрите [Контексты начальной загрузки](bootstrap-contexts.md), чтобы узнать, какие именно подсистемы инициализируются в каждом контексте, и [Обработка HTTP-запросов](http-request-handling.md) для API маршрутизатора и диспетчеризации.
---
## Сквозная загрузка — CLI
`src/console.php`:
1.`require bootstrap.php`; `XC_Bootstrap::boot(BootContext::Cli)` — DB, `LegacyInitializer`, необязательно Redis, заголовок процесса, затем **такой же**`populateContainer()` (таким образом, `events` и friends также существуют в CLI).
3.`new ModuleLoader; loadAll(); registerAllCommands($registry)` (команды модуля, **до**`bootAll`), затем `bootAll(getContainer())`**без маршрутизатора и трубопровода** — таким образом, маршруты и потоковое промежуточное программное обеспечение пропускаются; подключаются только службы модуля + подписчики событий.
4.`registry->dispatch($argv)` выполняет запрошенную команду.
---
## Что живет в другом месте
Чтобы избежать дублирования, информация об авторе и каждой подсистеме размещается на отдельных страницах: