Shopware 6核心服务装饰后新增方法调用问题(不可改核心代码)
Shopware 6装饰核心服务新增方法后调用报错的解决办法
问题场景
在不修改Shopware 6核心代码的前提下,通过装饰器给核心服务新增方法,调用时编辑器提示「undefined method」错误,相关代码及配置如下:
核心服务与装饰器代码
// 抽象类 abstract class AbstractCoreService { public function doSomething(); } // 核心服务实现类 class CoreService extends AbstractCoreService { public function doSomething(){ return 'I did Something'; } } // 装饰器类 class CoreServiceDecorator extends AbstractCoreService { public function doSomething(){ return 'I did Something More'; } public function doSomethingElse(){ return 'I did Something Else'; } }
装饰器XML配置
<service id="AbstractCoreService" alias="CoreService" /> <service id="CoreServiceDecorator" decorates="AbstractCoreService"> </service>
调用代码及配置
use AbstractCoreService; class DoRunService extends AbstractCoreService { private AbstractCoreService $coreService; public function __construct(AbstractCoreService $coreService) { $this->coreService = $coreService; } public function doSomething(){ return $this->coreService->doSomething(); } public function doRun(){ return $this->coreService->doSomethingElse(); // 此处编辑器提示`undefined method`错误 } }
对应的XML配置:
<service id="DoRunService"> <argument id="AbstractCoreService" type="service" /> </service>
问题原因
编辑器的静态类型检查基于你声明的AbstractCoreService类型,而这个抽象类中并没有定义doSomethingElse方法,因此会提示方法未定义。虽然运行时容器实际注入的是CoreServiceDecorator实例,但静态分析工具无法识别这一点。
解决方案
方案1:新增扩展接口(推荐)
通过新增接口来规范扩展方法,保证类型安全:
- 创建扩展接口,定义新增方法
- 让装饰器实现该接口
- 在调用类中依赖注入该接口类型
// 新增扩展接口 interface CoreServiceExtensionInterface { public function doSomethingElse(); } // 修改装饰器实现该接口 class CoreServiceDecorator extends AbstractCoreService implements CoreServiceExtensionInterface { public function doSomething(){ return 'I did Something More'; } public function doSomethingElse(){ return 'I did Something Else'; } } // 修改调用类的依赖类型 use AbstractCoreService; use CoreServiceExtensionInterface; class DoRunService extends AbstractCoreService { private CoreServiceExtensionInterface $coreService; public function __construct(CoreServiceExtensionInterface $coreService) { $this->coreService = $coreService; } public function doSomething(){ return $this->coreService->doSomething(); } public function doRun(){ return $this->coreService->doSomethingElse(); } }
方案2:强制类型转换(临时解决)
如果不想新增接口,可以通过类型注释告诉编辑器当前实例的真实类型:
public function doRun(){ /** @var CoreServiceDecorator $coreService */ $coreService = $this->coreService; return $coreService->doSomethingElse(); }
注意:这种方式牺牲了类型安全,后续装饰器结构变更可能引发运行时错误,不推荐长期使用。
方案3:使用服务别名注入装饰器
通过配置服务别名,直接注入装饰器实例:
- 在XML配置中给装饰器添加别名
<service id="CoreServiceDecorator" decorates="AbstractCoreService"> </service> <service alias="CoreServiceDecorator" id="AbstractCoreServiceExtension" />
- 修改调用类的依赖注入类型
use CoreServiceDecorator; class DoRunService extends AbstractCoreService { private CoreServiceDecorator $coreService; public function __construct(CoreServiceDecorator $coreService) { $this->coreService = $coreService; } public function doSomething(){ return $this->coreService->doSomething(); } public function doRun(){ return $this->coreService->doSomethingElse(); } }
- 更新调用类的XML配置
<service id="DoRunService"> <argument id="CoreServiceDecorator" type="service" /> </service>
内容的提问来源于stack exchange,提问作者IamArobot
相关产品推荐
相关产品推荐

