You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:45:37