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

Детский ДВС - синдром

Дочерний DIC имеет родительский указатель на главный DIC и действует аналогично главному DIC, но не совсем:

  • Всякий раз, когда set() вызывается на этом дочернем DIC, пара ключ - значение вставляется в дочерний контейнер.
  • Всякий раз, когда get() при вызове на нем ресурс получается из дочернего контейнера, но если он там не найден, то поиск также производится в родительском контейнере.

С версии Joomla 4 разработчики Joomla просят разработчиков расширений использовать внедрение зависимостей для их расширения путем определения файла services/provider.php. Затем загрузка расширения представляет собой двухэтапный процесс, который обрабатывается в файле services/provider.php:

  1. Класс расширения вводится в дочерний DIC
  2. Класс расширения извлекается из дочернего 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 функция экземпляра расширения, как описано в документации по расширению .