Laravel Service Provider中如何在被注入的B_Class里获取A_Class实例
你遇到的段错误是典型的循环依赖导致的:A_Class 构造方法依赖 B_Interface 实现,修改后的 B_Class 构造又依赖 A_Interface 实现,Laravel 依赖注入容器解析时会进入无限递归,最终触发内存溢出导致段错误。
方案1:Setter 注入(推荐)
通过构造后手动注入的方式绕开循环依赖,不需要修改原有绑定逻辑:
- 先给 B_Interface 新增设置 A 实例的契约方法:
<?php interface B_Interface { public function setA(A_Interface $a); public function method_1(); public function method_2(); // 其他原有方法 }
- 在 B_Class 中实现该方法,存储 A 实例供后续使用:
<?php class B_Class implements B_Interface { // 存储调用方A实例 private $a_instance; public function setA(A_Interface $a) { $this->a_instance = $a; } // 原有方法中需要调用A的地方直接使用 $this->a_instance 即可 }
- 修改 A_Class 的构造方法,注入 B 后直接把自身实例传给 B:
<?php class A_Class implements A_Interface { private $b_interface; public function __construct(B_Interface $b_interface) { $this->b_interface = $b_interface; // 手动注入当前A实例到B中 $this->b_interface->setA($this); } // 其他原有逻辑保持不变 }
方案2:闭包延迟解析
如果不方便修改 B 接口的定义,可以用闭包延迟获取 A 实例,避免构造时直接依赖:
- 修改 B_Class 构造方法,接收解析 A 的闭包而非直接注入 A 实例:
<?php class B_Class implements B_Interface { private $a_resolver; public function __construct(\Closure $a_resolver) { $this->a_resolver = $a_resolver; } // 需要使用A实例时调用该方法获取 private function getA() { return call_user_func($this->a_resolver); } // 其他原有方法保持不变 }
- 修改服务提供者的绑定逻辑,传入闭包解析器:
$this->app->when(A_Class::class) ->needs(B_Interface::class) ->give(function ($app) { return new B_Class(function () use ($app) { return $app->make(A_Interface::class); }); });
注意事项
- 方案1为最优解,不耦合容器特性,符合接口设计规范,兼容性最高
- 方案2使用时需要注意,如果 A_Interface 绑定的不是单例,需要自行确保解析到的是调用方的同一实例,避免逻辑异常
- 不要尝试在构造方法中互相直接注入实例,必然会触发循环依赖问题
内容的提问来源于stack exchange,提问作者leo95batista
相关产品推荐
相关产品推荐

