Почему некоторые классы определяют инъекции как в своем конструкторе, так и в di.xml?


12

Я не понимаю, почему в некоторых классах их инъекции зависимостей объявляются дважды - один раз в конструкторе di.xmlи в конкретном классе.

Например, в Magento\Backend\Model\Urlего di.xmlопределен набор типов для DI:

<type name="Magento\Backend\Model\Url">
    <arguments>
        <argument name="scopeResolver" xsi:type="object">
Magento\Backend\Model\Url\ScopeResolver</argument>
        <argument name="authSession" xsi:type="object">
Magento\Backend\Model\Auth\Session\Proxy</argument>
        <argument name="formKey" xsi:type="object">
Magento\Framework\Data\Form\FormKey\Proxy</argument>
        <argument name="scopeType" xsi:type="const">
Magento\Store\Model\ScopeInterface::SCOPE_STORE </argument>
        <argument name="backendHelper" xsi:type="object">
Magento\Backend\Helper\Data\Proxy</argument>
    </arguments>
</type>

Но в то же время в его конкретном классе те классы, определенные в di.xml, которые необходимы для внедрения, снова объявляются в конструкторе:

<?php
    public function __construct(
        \Magento\Framework\App\Route\ConfigInterface $routeConfig,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo,
        \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
        \Magento\Framework\Session\Generic $session,
        \Magento\Framework\Session\SidResolverInterface $sidResolver,
        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
        \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        $scopeType,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Backend\Model\Menu\Config $menuConfig,
        \Magento\Framework\App\CacheInterface $cache,
        \Magento\Backend\Model\Auth\Session $authSession,
        \Magento\Framework\Encryption\EncryptorInterface $encryptor,
        \Magento\Store\Model\StoreFactory $storeFactory,
        \Magento\Framework\Data\Form\FormKey $formKey,
        array $data = []
) {
    //...
}
?>

Если мы посмотрим на его конструктор выше, \Magento\Framework\App\Route\ConfigInterface $routeConfigнапример, не определен в di.xml. Он определен только в конструкторе, и Magento по-прежнему внедрит его routeConfigв класс для использования, не так ли? То же самое \Magento\Framework\Encryption\EncryptorInterface $encryptorи несколько других.

Тогда, почему существует необходимость определять другие внедрения в обоих di.xmlи в конструкторе, когда наличия этих объявлений в конструкторе достаточно для Magento, чтобы внедрить эти зависимости в класс для использования?

Ответы:


15

Как указано в документации , в Magento 2 di.xmlможно использовать следующее:

Вы можете настроить аргументы конструктора класса в вашем di.xmlузле аргументов. Менеджер объектов вводит эти аргументы в класс во время создания. Имя аргумента, настроенного в файле XML, должно соответствовать имени параметра в конструкторе в настроенном классе.

В вашем случае это немного сложно, я собираюсь объяснить каждый аргумент один за другим:

  • \Magento\Framework\App\Route\ConfigInterface $routeConfig: это интерфейс, поэтому его нельзя использовать напрямую . Предпочтение для этого класса определяетсяapp/etc/di.xml и это Magento\Framework\App\Route\Configкласс
  • \Magento\Framework\App\RequestInterface $request : то же самое касается этого класса, предпочтение Magento\Framework\App\Request\Http
  • \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo: тот же случай и здесь с Magento\Framework\Url\SecurityInfo\Proxyпредпочтением
  • \Magento\Framework\Url\ScopeResolverInterface $scopeResolver: здесь мы начнем с интересного. В app/etc/di.xmlпредпочтении определяется для этого интерфейса, и это Magento\Framework\Url\ScopeResolverкласс. Однако для Magento\Backend\Model\UrlMagento 2 необходимо использовать другой класс и, таким образом, он определяет, какой класс в опубликованном di.xmlвами тексте Magento\Backend\Model\Url\ScopeResolverбудет использоваться.
  • \Magento\Framework\Session\Generic $session это нормальный класс и, следовательно, может использоваться как есть.
  • \Magento\Framework\Session\SidResolverInterface $sidResolver: Обратно в интерфейс, предпочтение по - прежнему определяется в app/etc/di.xmlи этоMagento\Framework\Session\SidResolver\Proxy
  • \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory : это фабричный класс, поэтому его можно использовать как есть.
  • \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver: назад к нашему app/etc/di.xmlи предпочтениеMagento\Framework\Url\QueryParamsResolver
  • \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig: другой случай здесь, где ** предпочтение определено app/etc/di.xmlи оно есть Magento\Framework\App\Config.
  • $scopeType: здесь у нас есть только переменная без какого-либо класса перед ней. Ваш модуль di.xmlуказывает, что Magento\Store\Model\ScopeInterface::SCOPE_STOREследует использовать в качестве значения этой переменной. **
  • \Magento\Backend\Helper\Data $backendHelper: здесь мы могли бы использовать этот класс как есть. Однако здесь используется прокси, потому что этот класс не обязательно используется (см. Этот пост для получения подробной информации о прокси-классах: Magento 2: практическое объяснение, что такое прокси-класс? )
  • \Magento\Backend\Model\Menu\Config $menuConfig : мы можем использовать этот класс как есть.
  • \Magento\Framework\App\CacheInterface $cache: другое предпочтение, определенное app/etc/di.xmlдля этого интерфейса, котороеMagento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession: опять же, здесь мы могли бы использовать класс как есть, но вместо этого мы используем прокси-класс для отложенной загрузки.
  • \Magento\Framework\Encryption\EncryptorInterface $encryptor: app/etc/di.xmlснова прыгаем и находим Magento\Framework\Encryption\Encryptorв качестве предпочтения
  • \Magento\Store\Model\StoreFactory $storeFactory : фабрика, чтобы мы могли использовать ее как есть.
  • \Magento\Framework\Data\Form\FormKey $formKey: здесь мы Magento\Framework\Data\Form\FormKey\Proxyснова используем прокси-класс для отложенной загрузки.
  • array $data = []: этот всегда идет последним и автоматически устанавливается по умолчанию в пустой массив, вы можете найти больше информации здесь: Magento 2: что такое параметр конструктора массива $ data?

Подвести итоги

Глобально, параметры конструкторов классов являются интерфейсами или неинстанцируемыми классами. Таким образом, di.xmlвы можете настроить зависимости, которые вы хотите использовать для каждого конструктора класса. Это также верно для инстанцируемых классов. Например, конструктор класса, который принимает класс продукта в качестве аргумента конструктора. Его можно адаптировать в настраиваемом модуле продукта, чтобы вместо него в качестве аргумента использовался настраиваемый класс продукта.


Всегда ли предпочтение требуется для параметра интерфейса? Это можно рассматривать как запасной вариант? Имеет ли смысл просто указывать конкретный аргумент в конфигурации без каких-либо предпочтений? Или это невозможно?
robsch

6

Важно понимать разницу между определением зависимостей и настройкой зависимостей.

Зависимости не определены внутри di.xml. Зависимости определяются внутри конструктора соответствующего класса путем указания интерфейса, реферата или фабрики в качестве типа этой конкретной зависимости, например, $routeConfigзависимости типа \Magento\Framework\App\Route\ConfigInterface.

С другой стороны, di.xmlэто место для настройки зависимостей с использованием <preference/>узлов и / или xpath:type/arguments/argumentузлов (иногда в сочетании с более сложными узлами конфигурации, такими как <virtualType/>или <proxy/>). Настройка зависимости просто означает сопоставление аргумента конструктора объекта с реализацией / объектом / конкретным .

Вы хотите, чтобы зависимости конфигурировались с помощью di.xml, чтобы вы могли поменять их местами и использовать другую реализацию для определенного интерфейса или аргумента при определенных условиях (продолжайте читать пример, чтобы понять, что должны означать определенные условия).

Например, при разработке вашего расширения вы сначала должны создать новый класс (мы называем этот новый класс реализацией ). Ваш новый класс реализует \Magento\Framework\App\Route\ConfigInterfaceинтерфейс, и в его теле есть конкретная функциональность, которая выполняет контракт интерфейса. Теперь запускаем часть конфигурации : чтобы указать Magento использовать вашу недавно определенную реализацию, вы должны сконфигурировать эту реализацию как зависимость для объекта Magento\Backend\Model\Url . Вы делаете эту конфигурацию внутри di.xmlфайлов или вашего модуля. В этом случае вам нужно использовать <preference/>узел для сопоставления интерфейса с вашей новой реализацией. В других случаях вы бы использовали более гранулированный xpath:type/arguments/argument di.xmlузел дляотображать только конкретные аргументы (или зависимости, или интерфейсы) конкретного объекта в конкретные реализации . Теперь ваша реализация будет активна в качестве зависимости для объекта только \Magento\Backend\Model\Url в определенных условиях , например, в потоке выполнения кода текущего запроса приложения создается объект типа Magento\Backend\Model\Url, и требуется реализация для определенной конструктором зависимости, $routeConfigкоторая называется типа \Magento\Framework\App\Route\ConfigInterface.

Это почти как сказать:

«Привет, мистер ObjectManager! Всякий раз, когда Magento\Backend\Model\Urlзапрашивается экземпляр объекта типа , сначала посмотрите на его определение конструктора класса и проанализируйте определенные в нем зависимости . Я хочу, чтобы вы затем посмотрели в окончательном объединенном di.xmlтекущем HTTP-запросе конфигурацию для каждой настроенной зависимости , определенной в конструкторе класса Magento \ Backend \ Model \ Url . Вы даете мне эту настроенную реализацию зависимости. "

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.