Magento 2中dependency与dependency injection基础定义及实际示例咨询
基础概念定义
依赖(Dependency)
当一个类要完成自身功能必须调用另一个类的能力时,我们就称前者对后者存在依赖。这是面向对象编程中对象协作的天然属性,本身没有好坏,问题出在不合理的依赖管理方式上。
依赖注入(Dependency Injection, DI)
是一种专门用于管理依赖的设计模式,核心逻辑是:类不需要自行实例化它依赖的对象,而是由外部的DI容器负责依赖对象的实例化、配置,再将其注入到需要用到该依赖的类中。
这种模式的核心价值是解耦,让类只依赖约定的接口,不依赖具体实现,大幅提升代码的可扩展性、可测试性。
Magento 2 场景实战示例
Magento 2 框架原生实现了成熟的DI容器,是框架核心能力之一,所有业务代码都推荐遵循DI规范编写。
反面示例:硬编码依赖(错误写法)
假设你需要开发一个订单导出类,如果你选择在类内部自行实例化依赖的订单查询类,代码如下:
class OrderExporter { protected $orderRepo; public function __construct() { // 硬编码实例化具体实现类,耦合度极高 $this->orderRepo = new \Magento\Sales\Model\OrderRepository(); } public function exportById(int $orderId): array { $order = $this->orderRepo->get($orderId); // 省略订单数据格式化、导出逻辑 return $order->getData(); } }
这种写法的问题非常明显:
- 如果你后续想要给订单查询增加缓存能力,替换自定义的订单仓库实现,必须修改
OrderExporter类的构造函数代码 - 单元测试时无法Mock
OrderRepository类,必须连接真实数据库才能测试导出逻辑,测试成本极高
正面示例:使用Magento DI规范编写(正确写法)
Magento 2中要求所有依赖都在构造函数中声明,由DI容器自动注入,依赖优先声明为接口而非具体实现:
class OrderExporter { protected $orderRepo; // 构造函数中声明依赖的接口,不需要自己实例化 public function __construct( \Magento\Sales\Api\OrderRepositoryInterface $orderRepo ) { $this->orderRepo = $orderRepo; } public function exportById(int $orderId): array { $order = $this->orderRepo->get($orderId); // 省略订单数据格式化、导出逻辑 return $order->getData(); } }
如果需要替换OrderRepositoryInterface的实现,只需要在你自定义模块的di.xml中配置偏好即可,不需要修改OrderExporter的任何代码:
<!-- app/code/你的开发商名/你的模块名/etc/di.xml --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <!-- 配置接口对应的实现类,DI容器会自动按这个配置注入 --> <preference for="Magento\Sales\Api\OrderRepositoryInterface" type="你的开发商名\你的模块名\Model\CachingOrderRepository" /> </config>
这种写法的优势:
- 依赖替换完全通过配置实现,原有业务代码零修改,符合开闭原则
- 单元测试时可以直接传入Mock的
OrderRepositoryInterface实例,不需要连接数据库就能完成导出逻辑测试 - 所有依赖的实例化统一由DI容器管理,避免重复创建对象,性能更优
内容的提问来源于stack exchange,提问作者Ekta Rathod
相关产品推荐
相关产品推荐

