Чому деякі класи визначають ін'єкції як у конструкторі, так і у 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запитується, будь ласка , зверніть увагу на його клас визначення конструктора перший і аналізувати dependecies певне в ньому. Я хочу , щоб ви потім для пошуку в фіналі, злитий di.xmlз поточного запиту HTTP по конфігурації для кожної налаштованої залежності , визначеної в конструкторі класу Magento \ Backend \ Model \ Url . Ви даєте мені цю налаштовану реалізацію залежності. "

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.