系统学习magento二次开发,推荐小册:《Magento中文全栈二次开发 》
本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。
magento2中的proxy是一种设计模式,比较难于理解,本篇内容将为大家介绍magento2中的代理模式:proxy
当对象创建成本很高,并且类的构造函数占用了大量资源时,就会使用代理类。为了避免不必要的性能影响,
Magento使用Proxy类将给定的类型变成它们的延迟加载版本。
在所有Magento di.xml文件中快速查找\Proxy</argument>字符串可以发现该字符串出现了一百多次。
可以说,Magento在其代码中广泛使用代理。
<MAGENTO_DIR>/module-customer/etc/di.xml下的类型定义是使用代理的一个很好的例子:
<type name="Magento\Customer\Model\Session"> <arguments> <argument name="configShare" xsi:type="object">Magento\Customer\Model\Config\Share\Proxy</argument> <argument name="customerUrl" xsi:type="object">Magento\Customer\Model\Url\Proxy</argument> <argument name="customerResource" xsi:type="object">Magento\Customer\Model\ResourceModel\Customer\Proxy</argument> <argument name="storage" xsi:type="object">Magento\Customer\Model\Session\Storage</argument> <argument name="customerRepository" xsi:type="object">Magento\Customer\Api\CustomerRepositoryInterface\Proxy</argument> </arguments> </type>
如果我们查看Magento\Customer\Model\Session类型的构造函数,我们可以看到四个参数
(configShare、customerUrl、customerResource和customerRepository)中,
没有一个在PHP文件中声明为Proxy。它们是通过di.xml重写的。
这些代理类型还不真正存在,因为Magento依赖注入(di)编译过程创建了它们。
它们是在生成的目录下自动生成的。
编译后,可以在生成的/code/Magento/Customer/Model/Url/Proxy.php
文件下轻松找到Magento\Customer\Model\Url\Proxy.php类型。
让我们局部来看一下:
<?php class Proxy extends\ Magento\ Customer\ Model\ Url implements\ Magento\ Framework\ ObjectManager\ NoninterceptableInterface { public function __construct(\Magento\ Framework\ ObjectManagerInterface $objectManager, $instanceName = '\\Magento\\Customer\\Model\\Url', $shared = true) { $this - > _objectManager = $objectManager; $this - > _instanceName = $instanceName; $this - > _isShared = $shared; } public function __sleep() { return ['_subject', '_isShared', '_instanceName']; } public function __wakeup() { $this - > _objectManager = \Magento\ Framework\ App\ ObjectManager::getInstance(); } public function __clone() { $this - > _subject = clone $this - > _getSubject(); } protected function _getSubject() { if (!$this - > _subject) { $this - > _subject = true === $this - > _isShared ? $this - > _objectManager - > get($this - > _instanceName) : $this - > _objectManager - > create($this - > _instanceName); } return $this - > _subject; } public function getLoginUrl() { return $this - > _getSubject() - > getLoginUrl(); } public function getLoginUrlParams() { return $this - > _getSubject() - > getLoginUrlParams(); } }
Proxy类的组成显示了它包装原始Magento\Customer\Model\Url类型的机制。这意味着,在整个Magento中,
每次请求Magento\Customer\Model\Url类型时,
Magento\Customer\Module\Url\Proxy都会被传递。与原始类型的__construct方法(可能会影响性能)不同,
自动生成代理的__construction方法是轻量级的。这消除了可能的性能瓶颈。_getSubject方法用于在调用任何原始类型的公共方法时,
实例化/延迟加载原始类型。
例如,对getLoginUrl方法的调用将通过代理。
Magento生成的每个代理都实现了Magento\Framework\ObjectManager\NoninterceptableInterface。
尽管接口本身是空的,但它被用作标识代理的标记,
我们不需要为其生成拦截器(插件)。
class Customer { public function __construct(\Magento\ Customer\ Model\ Url\ Proxy $customerUrl) { //... }}
然而,这种做法是一种糟糕的做法。正确执行此操作的方法是使用原始Magento\Customer\Model\Url类型指定__construct,
然后按如下方式添加di.xml:
<type name="Magelicious\Core\Model\Customer"> <arguments> <argument name="customerUrl" xsi:type="object">Magento\Customer\Model\Url\Proxy</argument> </arguments> </type>