简体   繁体   中英

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

There seems to be two ways to dynamically instantiate a service in Symfony:

Both methods seem to be current. Inspecting the issues and changelog didn't give me any more informations on which is the most common or which method is considered best practice.

So, should I be using service factory over service configurator or service configurator over factory? Why and which is the more recent?

Thanks a lot!

Basically, their not the same: a factory is used to create the service, the configurator is used to configure it after its creation.

Use standard service configuration file (ie.: services.yml ) when you need to instantiate a service (and maybe inject other services or parameters).

Use the factory when you need to take control over service instantiation.

Use service configurator when you need to configure your service, after creation, and you want to keep service definition separate from service configuration.

Using service factory over service configurator is better decision in a few special cases:

1) Creating service definitions for older PHP classes since, in the past, creation logic was often hidden inside static factory classes For example, 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) One particularly nice example of using a factory service and method for retrieving a service is the case of a Doctrine repository. When you need one, you would normally inject an entity manager as a constructor argument and later retrieve a specific repository:

use Doctrine\ORM\EntityManager;

class SomeClass
{
    public function __construct(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function doSomething()
    {
        $repository = $this->entityManager->getRepository('User');
    }
}

But using a factory service and method you could directly inject the correct repository itself:

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>

By looking at the constructor arguments of SomeClass it is immediately clear that it needs a User repository, which is much more specific and communicative than the earlier example in which SomeClass needed an EntityManager . Besides making the class itself much cleaner, it will also make it much easier to create a stand-in object for the repository when you are writing a unit test for this class. Instead of creating a mock for both the entity manager and the repository, you only have to create one for the repository itself.

Drawbacks of using service factory are (according to Matthias):

My objection to factory classes with static factory methods is that static code is global code and that executing that code may have side effects that can not be isolated (for instance in a test scenario). Besides, any dependency of such a static factory method has to be by definition static itself, which is also really bad for isolation and prevents you from replacing (part of) the creation logic by your own code. Factory objects (or factory services) are slightly better. However, the need for them very likely points to some kind of design problem. A service should not need a factory, since it will be created only once in a predetermined (and deterministic) way and from then on be perfectly reusable by any other object. The only things that are dynamic about a service, should be the arguments of the methods that are part of its public interface

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM