PHP子类B复用父类A构造的$foo且无需重复父类构造参数的实现方案
解决方案思路
思路一:重构父类,拆分初始化逻辑
把父类A中$foo的初始化逻辑抽成独立方法,子类B无需调用完整的父类构造,仅调用该初始化方法就能获取$foo。
修改后代码:
class A extends AbstractController { protected FooController $foo; protected EntityManagerInterface $manager; protected Security $security; protected RequestStack $requestStack; public function __construct(EntityManagerInterface $manager, Security $security, RequestStack $requestStack) { $this->manager = $manager; $this->security = $security; $this->requestStack = $requestStack; $this->initFoo(); } // 抽离foo的初始化逻辑为独立方法 protected function initFoo(): void { $this->foo = new FooController(); } } class B extends A { private $someVariable; public function __construct($some_variable) { // 直接调用父类方法初始化foo,无需传入父类构造的一堆依赖 $this->initFoo(); // 处理自身参数,注意不要覆盖foo(除非你本意是替换) $this->someVariable = $some_variable; } }
注:如果B不需要使用A中的$manager、$security等属性,该方案完全适用;若B需要这些属性,可结合依赖容器进一步处理。
思路二:利用依赖注入容器(适配Symfony环境)
由于类继承了AbstractController,大概率运行在Symfony框架中。可借助容器自动注入A的依赖,同时让B的构造仅保留自身所需参数。
构造注入方式
class B extends A { private $someVariable; // 容器自动注入A的依赖,同时添加自身参数 public function __construct( EntityManagerInterface $manager, Security $security, RequestStack $requestStack, $some_variable ) { parent::__construct($manager, $security, $requestStack); $this->someVariable = $some_variable; } }
调用时直接通过容器获取实例:
// 控制器中通过参数注入获取B实例 public function index(B $b) { // 使用$b->foo } // 或手动从容器获取 $b = $this->container->get(B::class);
属性注入方式(Symfony 5.4+支持)
若不想在B的构造中写一堆父类依赖,可使用属性注入:
class B extends A { private $someVariable; public function __construct($some_variable) { $this->someVariable = $some_variable; $this->initFoo(); // 需先按思路一重构A } // 自动注入父类所需依赖(若B需要使用) #[Autowire] protected EntityManagerInterface $manager; #[Autowire] protected Security $security; #[Autowire] protected RequestStack $requestStack; }
思路三:使用工厂方法创建实例
编写工厂类处理A的依赖注入,外部调用工厂仅需传入$some_variable即可创建B实例:
class BFactory { private $manager; private $security; private $requestStack; // 工厂注入A所需的全部依赖 public function __construct( EntityManagerInterface $manager, Security $security, RequestStack $requestStack ) { $this->manager = $manager; $this->security = $security; $this->requestStack = $requestStack; } public function create(string $someVariable): B { $b = new B($someVariable); // 用反射给B设置父类属性并初始化foo $reflection = new ReflectionClass($b); // 设置manager属性 $managerProp = $reflection->getProperty('manager'); $managerProp->setAccessible(true); $managerProp->setValue($b, $this->manager); // 设置security属性 $securityProp = $reflection->getProperty('security'); $securityProp->setAccessible(true); $securityProp->setValue($b, $this->security); // 设置requestStack属性 $requestStackProp = $reflection->getProperty('requestStack'); $requestStackProp->setAccessible(true); $requestStackProp->setValue($b, $this->requestStack); // 调用父类initFoo方法初始化foo $initFooMethod = $reflection->getMethod('initFoo'); $initFooMethod->setAccessible(true); $initFooMethod->invoke($b); return $b; } } // 调用方式 $b = $this->container->get(BFactory::class)->create('foo');
该方案适合不想大幅修改原有类结构的场景,反射带来的性能损耗在常规业务场景可忽略。
内容的提问来源于stack exchange,提问作者endo.anaconda
相关产品推荐
相关产品推荐

