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

mcm*_*phy 6 php constructor dependency-injection symfony

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

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

目前,我将“通用”参数作为每个方法中的最后一个参数传递,如下所示:

/**
 * @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");
}
Run Code Online (Sandbox Code Playgroud)

这样做可以让我消除我的__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");
}
Run Code Online (Sandbox Code Playgroud)

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

以一种方式与另一种方式相比有优势吗?

谢谢。

Nic*_*asB 5

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

  • 不太容易受到parent::__construct方法变化的影响。在构造函数上使用 DI 意味着您必须在发生变化时调整代码。还要注意,一些 Symfony 捆绑包可能会假设控制器具有特定的签名,如果没有,它可能会使事情变得更加复杂。
  • 如果至少有一个路由不使用该服务,通过使用这些细粒度的 DI,我们可以避免在不需要时实例化服务(如果它有自己的 DI 并且没有在其他地方使用,这可能会很昂贵) . 不过,这主要可以通过使用惰性服务来抵消。

在构造函数中使用 DI 的原因:

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

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

您还可以使用setter 注入并以这种方式配置您的服务。这在功能上与在构造函数中使用 DI 非常相似,但它绕过了从父构造生成不同签名的主要缺点,并且在父构造函数更改时需要更多的维护工作。

您还可以使其更易于用于您经常注入的服务。使需要此 DI 的服务实现一个接口并使用_instanceof对其进行配置。Symfony 用它来做到这一点,ContainerAwareInterface甚至还有一个ContainerAwareTrait以声明 setter 和属性的形式的促进器。在您的情况下,如果多个服务需要该MySqlGroupDAO服务,您可以定义一个MySqlGroupDAOAwareTraitand MySqlGroupDAOAwareInterfaceMySqlGroupDAOAwareInterface在您services.yaml_instanceof部分添加一个条目,并使用该特征并在需要 DI 的服务中实现该接口。