为什么有些类在其构造函数和di.xml中都定义了注入?


12

我不明白为什么在某些类中,它们的依赖项注入要声明两次-一次在di.xml和具体类的构造函数中进行。

例如,在中Magento\Backend\Model\Urldi.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将这些依赖项注入到类中以供使用时,为什么需要在构造函数和构造函数中都定义其他注入?

Answers:


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 $cacheapp/etc/di.xml为此接口定义的另一个首选项是Magento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession同样,在这里我们可以使用该类,但是我们使用代理类代替延迟加载。
  • \Magento\Framework\Encryption\EncryptorInterface $encryptorapp/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中定义。依赖关系构造内限定通过指定的接口,一个抽象的或工厂作为各个类的类型特定dependecy,例如$routeConfig是类型的依赖\Magento\Framework\App\Route\ConfigInterface

另一方面,di.xml使用<preference/>节点和/或xpath:type/arguments/argument节点(有时与更高级的配置节点(例如<virtualType/><proxy/>)耦合)配置依赖项的地方。配置依赖项仅意味着将对象的构造函数参数映射到Implementation / object / concrete

你想依赖是配置通过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类构造函数中定义的每个已配置的依赖项,您都可以给我该已配置的依赖项实现。”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.