Symfony 4服务依赖注入-构造函数与方法

时间:2018-10-10 02:19:15

标签: php symfony dependency-injection constructor

所以我有一个Symfony控制器,并且正在通过参数将所需的服务注入到我的方法中。

此控制器类的所有方法都使用一种参数(MySqlGroupDAO $groupDAO)。

目前,我正在将“ common”参数作为每种方法中的最后一个参数传递:

/**
 * @Route("/{id}", methods={"POST"})
 * @IsGranted("EDIT_GROUP", subject="parentGroup")
 */
public function addGroup(Request $request, MySqlGroupDAO $groupDAO)  {
    $group = new Group();
    //code to init group from request

    $groupDAO->addGroup($group);

    return new Response("Adding $groupName");
}

以这种方式进行操作可以消除我的__construct方法。但是,我不确定这是否是最好的方法。由于在所有方法中都是通用的,因此最好重新添加构造函数并执行类似的操作?:

private $groupDAO;

public function __construct(
    Config $config,
    ValidatorInterface $validator,
    TranslatorInterface $translator,
    RequestStack $requestStack
) {
    parent::__construct($config, $validator, $translator, $requestStack);
    $this->groupDAO = new MySqlGroupDAO($config);
}


/**
 * @Route("/{id}", methods={"POST"})
 * @IsGranted("EDIT_GROUP", subject="parentGroup")
 */
public function addGroup(Request $request)  {
    $group = new Group();
    //code to init group from request

    $this->groupDAO->addGroup($group);

    return new Response("Adding $groupName");
}

这样做,我消除了所有方法(在此特定类中)的六个参数。但是我要重新添加构造函数,这需要我添加一个类参数,并在其构造函数中注入几个其他参数,因为它扩展了另一个类。

一种方法相对于另一种方法有优势吗?

谢谢。

1 个答案:

答案 0 :(得分:4)

导致在控制器的路由方法中使用DI的原因:

  • 较少受到parent::__construct方法更改的影响。在构造函数上使用DI意味着每次更改时都必须调整代码。还请注意,某些Symfony捆绑包可能会假定控制器具有特定的签名,如果没有,则可能会使您的事情变得更复杂。
  • 如果至少一条路由不使用该服务,则通过使用这些细粒度的DI,我们避免了在不必要的情况下实例化服务(如果它具有自己的DI尚未使用,则可能会非常昂贵别的地方)。不过,可以使用lazy services来弥补这一点。

在构造器中使用DI的原因:

  • 在控制器以外的服务中(以及在控制器的路由方法以外的方法中,如果有的话),您不能使用自动装配。如果要使用方法的参数注入依赖项,则必须在每次调用时手动传递该依赖项。这依次意味着,调用该方法的任何服务本身都应在所需服务上具有DI。因此,该问题已转移,但不能以这种方式无限转移,并且在某个时候,您将希望对父级使用一些自动装配。

在构造函数中使用DI的替代方法:

您还可以使用setter injection并配置服务this way。这在功能上与在构造函数中使用DI十分相似,但是它绕过了主要缺点,即与父代生成不同的签名,并且如果父代构造函数发生更改,则需要进行更多的维护工作。

您还可以使其更易于用于经常注入的服务。使需要此DI的服务实现一个接口,并使用_instanceof对其进行配置。 Symfony使用其ContainerAwareInterface来做到这一点,甚至以ContainerAwareTrait的形式提供了一个促进者来声明setter和属性。在您的情况下,如果几个服务需要MySqlGroupDAO服务,则可以定义MySqlGroupDAOAwareTraitMySqlGroupDAOAwareInterface,并在MySqlGroupDAOAwareInterface的{ {1}}部分,并使用trait并在需要DI的服务中实现接口。