04 - Расширения и дочерние Контейнеры
Всякий раз, когда Joomla загружает расширение, она создает дочерний DIC исключительно для использования этого расширения. Это показано схематически ниже.

Дочерний DIC имеет родительский указатель на главный DIC и действует аналогично главному DIC, но не совсем:
- Всякий раз, когда
set()вызывается на этом дочернем DIC, пара ключ - значение вставляется в дочерний контейнер. - Всякий раз, когда
get()при вызове на нем ресурс получается из дочернего контейнера, но если он там не найден, то поиск также производится в родительском контейнере.
С версии Joomla 4 разработчики Joomla просят разработчиков расширений использовать внедрение зависимостей для их расширения путем определения файла services/provider.php. Затем загрузка расширения представляет собой двухэтапный процесс, который обрабатывается в файле services/provider.php:
- Класс расширения вводится в дочерний DIC
- Класс расширения извлекается из дочернего DIC, создавая экземпляр класса
Давайте рассмотрим минимальный пример этого для com_example с пространством имен Mycompany\Component\Example.
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Mycompany\Component\Example\Administrator\Extension\ExampleComponent;
return new class implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new ExampleComponent();
return $component;
}
);
}
};
Мы можем видеть, что когда Joomla выполняет require этого php-файла, то он вернет экземпляр класса
$provider = require $path; // $path points to the relevant services/provider.php file
Переменная $provider затем указывает на объект, являющемся экземпляром этого анонимного класса. Также класс реализует Joomla\DI\ServiceProviderInterface, что в основном означает, что у него есть метод, называемый register с приведенной выше подписью.
Когда в следующий раз Joomla сделает
if ($provider instanceof ServiceProviderInterface) {
$provider->register($container);
в register будет вызвана функция, которая поместит в дочернюю DIC запись с
- key = ComponentInterface::class – это просто сокращенный способ PHP указать строку 'Joomla \ CMS \ Extension \ComponentInterface'
- value = функция, возвращая новый экземпляр ExampleComponent, который является классом расширения
com_example
Затем, когда Joomla выполняет код:
$extension = $container->get($type);
приведенная выше функция будет запущена и вернет новый экземпляр ExampleComponent.
Вы можете самостоятельно ознакомиться с кодом Joomla в разделе libraries/src/Extension/ExtensionManagerTrait.php и подтвердить, что приведенный выше шаблон также применим к модулям и плагинам.
Обратите также внимание на следующую строку в этом файле:
if ($extension instanceof BootableExtensionInterface) {
$extension->boot($container);
}
Итак, если класс расширения реализует BootableExtensionInterface тогда Joomla немедленно вызовет boot функция экземпляра расширения, как описано в документации по расширению .