2

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!

Hussard
  • 656
  • 7
  • 14
  • As several other people have requested, post more info on your specific use case. In particular, distinguish between "compile time" configuration and request based "run time" configuration. – Cerad Nov 14 '16 at 13:45

2 Answers2

3

Basically, they're not the same:

  1. A factory is used to create the service
  2. The configurator is used to configure it after its creation

Use standard service configuration file (i.e. 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.

James
  • 4,644
  • 5
  • 37
  • 48
DonCallisto
  • 29,419
  • 9
  • 72
  • 100
  • Do you a real life example of when to use Service Configurators then? Basically, one of my service argument is dynamically defined at runtime, info being 'found' via the filesystem. http://stackoverflow.com/questions/23156907/how-can-i-dynamically-set-a-parameter-in-symfony2 – Hussard Nov 14 '16 at 11:50
  • @Hussard If you read the docs you've linked, you'll find out real use cases – DonCallisto Nov 14 '16 at 12:14
0

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

Matko Đipalo
  • 1,676
  • 1
  • 11
  • 23
  • Do you a real life example of when to use Service Configurators then? Basically, one of my service argument is dynamically defined at runtime, info being 'found' via the filesystem. http://stackoverflow.com/questions/23156907/how-can-i-dynamically-set-a-parameter-in-symfony2 – Hussard Nov 14 '16 at 11:50
  • Could you update your original question with the code of your dynamic service? – Matko Đipalo Nov 14 '16 at 12:53