Symfony——使用服务工厂还是服务配置器更好?


Symfony - Is it better to use a service factory or a service configurator?

在Symfony中似乎有两种动态实例化服务的方法:

  • 使用工厂(https://symfony.com/doc/current/service_container/factories.html)
  • 使用配置器(https://symfony.com/doc/current/service_container/configurators.html)

两种方法似乎都是当前的。检查问题和更改日志并没有给我任何关于哪种方法是最常见的或哪种方法被认为是最佳实践的更多信息。

那么,我应该使用服务工厂而不是服务配置器还是服务配置器而不是工厂?为什么,哪个是最近的?

非常感谢!

基本上,它们是不一样的:

  1. 工厂用于创建服务
  2. 配置器用于在其创建后对其进行配置

当你需要实例化一个服务(可能注入其他服务或参数)时,使用标准服务配置文件(即services.yml)。

当你需要控制服务实例化时,使用工厂。

当您需要在创建后配置服务,并且希望将服务定义与服务配置分开时,请使用service configurator

在一些特殊情况下,使用服务工厂而不是服务配置器是更好的选择:

1)为旧的PHP类创建服务定义,因为在过去,创建逻辑通常隐藏在静态工厂类中例如,Doctrine_Core::getTable()

public static function getTable($componentName)
{
    return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName);
}
https://github.com/doctrine/doctrine1/blob/master/lib/Doctrine/Core.php

2)使用工厂服务和方法检索服务的一个特别好的例子是原则存储库的案例。当需要实体管理器时,通常会将实体管理器注入为构造函数参数,稍后检索特定的存储库:

use Doctrine'ORM'EntityManager;
class SomeClass
{
    public function __construct(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }
    public function doSomething()
    {
        $repository = $this->entityManager->getRepository('User');
    }
}

但是使用工厂服务和方法,你可以直接注入正确的存储库本身:

class SomeClass
{
    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }
}

<service id="some_service" class="SomeClass">
    <argument type="user_repository" />
</service>

<service id="user_repository" class="UserRepository"
   factory-service="entity_manager" factory-method="getRepository">
   <argument>User</argument>
</service>

通过查看SomeClass的构造函数参数,可以立即清楚地看出它需要一个用户存储库,它比前面的示例更加具体和交流someeclass需要一个EntityManager。除了使类本身更加干净之外,它还将使在编写单元测试时,为存储库创建替代对象要容易得多类。您不需要同时为实体管理器和存储库创建模拟,只需这样做为存储库本身创建一个。

  • 示例来自Matthias Noback的书 Symfony的一年:编写健康的,可重用的Symfony2代码,第6章,服务模式https://leanpub.com/a-year-with-symfony

使用服务工厂的缺点是(根据Matthias):

我反对使用静态工厂方法的工厂类是这样的静态代码是全局代码,执行该代码可能会有副作用不能被隔离的效果(例如在测试场景中)。此外,这种静态工厂方法的任何依赖都必须由定义静态本身,这对于隔离和防止您用自己的逻辑替换(部分)创建逻辑代码。工厂对象(或工厂服务)稍好一些。然而,对它们的需求很可能指向某种设计问题。服务不应该需要工厂,因为它将被创建只有一次以预定的(和确定的)方式,从那时起可以被任何其他对象完全重用。唯一的东西是动态的关于一个服务,应该是方法的参数都是其公共接口

的一部分