The DependencyInjection Component

    Note

    If you install this component outside of a Symfony application, you mustrequire the file in your code to enable the classautoloading mechanism provided by Composer. Readthis article for more details.

    This article explains how to use the DependencyInjection features as anindependent component in any PHP application. Read the article to learn about how to use it in Symfony applications.

    You might have a class like the following Mailer thatyou want to make available as a service:

    1. class Mailer
    2. {
    3. private $transport;
    4.  
    5. public function __construct()
    6. {
    7. $this->transport = 'sendmail';
    8. }
    9.  
    10. // ...
    11. }

    You can register this in the container as a service:

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2.  
    3. $containerBuilder = new ContainerBuilder();
    4. $containerBuilder->register('mailer', 'Mailer');

    An improvement to the class to make it more flexible would be to allowthe container to set the transport used. If you change the classso this is passed into the constructor:

    1. class Mailer
    2. {
    3. private $transport;
    4.  
    5. public function __construct($transport)
    6. {
    7. $this->transport = $transport;
    8. }
    9.  
    10. // ...
    11. }

    Then you can set the choice of transport in the container:

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2.  
    3. $containerBuilder = new ContainerBuilder();
    4. $containerBuilder
    5. ->register('mailer', 'Mailer')
    6. ->addArgument('sendmail');

    This class is now much more flexible as you have separated the choice oftransport out of the implementation and into the container.

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2.  
    3. $containerBuilder = new ContainerBuilder();
    4. $containerBuilder->setParameter('mailer.transport', 'sendmail');
    5. $containerBuilder
    6. ->register('mailer', 'Mailer')
    7. ->addArgument('%mailer.transport%');

    Now that the mailer service is in the container you can inject it asa dependency of other classes. If you have a NewsletterManager classlike this:

    When defining the newsletter_manager service, the service doesnot exist yet. Use the Reference class to tell the container to inject themailer service when it initializes the newsletter manager:

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2. use Symfony\Component\DependencyInjection\Reference;
    3.  
    4. $containerBuilder = new ContainerBuilder();
    5.  
    6. $containerBuilder->setParameter('mailer.transport', 'sendmail');
    7. $containerBuilder
    8. ->register('mailer', 'Mailer')
    9. ->addArgument('%mailer.transport%');
    10.  
    11. $containerBuilder
    12. ->register('newsletter_manager', 'NewsletterManager')
    13. ->addArgument(new Reference('mailer'));

    If the NewsletterManager did not require the Mailer and injectingit was only optional then you could use setter injection instead:

    1. class NewsletterManager
    2. {
    3. private $mailer;
    4. public function setMailer(\Mailer $mailer)
    5. {
    6. $this->mailer = $mailer;
    7. }
    8.  
    9. // ...
    10. }

    You can now choose not to inject a Mailer into the NewsletterManager.If you do want to though then the container can call the setter method:

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2. use Symfony\Component\DependencyInjection\Reference;
    3.  
    4. $containerBuilder = new ContainerBuilder();
    5.  
    6. $containerBuilder->setParameter('mailer.transport', 'sendmail');
    7. $containerBuilder
    8. ->register('mailer', 'Mailer')
    9. ->addArgument('%mailer.transport%');
    10.  
    11. $containerBuilder
    12. ->register('newsletter_manager', 'NewsletterManager')
    13. ->addMethodCall('setMailer', [new Reference('mailer')]);

    You could then get your service from the containerlike this:

    1. use Symfony\Component\DependencyInjection\ContainerBuilder;
    2.  
    3. $containerBuilder = new ContainerBuilder();
    4.  
    5. // ...
    6.  
    7. $newsletterManager = $containerBuilder->get('newsletter_manager');

    Whilst you can retrieve services from the container directly it is bestto minimize this. For example, in the NewsletterManager you injectedthe mailer service in rather than asking for it from the container.You could have injected the container in and retrieved the mailer servicefrom it but it would then be tied to this particular container making itdifficult to reuse the class elsewhere.

    As well as setting up the services using PHP as above you can also useconfiguration files. This allows you to use XML or YAML to write the definitionsfor the services rather than using PHP to define the services as in theabove examples. In anything but the smallest applications it makes senseto organize the service definitions by moving them into one or more configurationfiles. To do this you also need to installthe Config component.

    Loading an XML config file:

    1. use Symfony\Component\Config\FileLocator;
    2. use Symfony\Component\DependencyInjection\ContainerBuilder;
    3. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
    4.  
    5. $containerBuilder = new ContainerBuilder();
    6. $loader = new XmlFileLoader($containerBuilder, new FileLocator(__DIR__));
    7. $loader->load('services.xml');

    Loading a YAML config file:

    Note

    If you want to load YAML config files then you will also need to install.

    Tip

    If your application uses unconventional file extensions (for example, yourXML files have a .config extension) you can pass the file type as thesecond optional parameter of the load() method:

    1. // ...
    2. $loader->load('services.config', 'xml');

    If you do want to use PHP to create the services then you can move thisinto a separate config file and load it in a similar way:

    1. use Symfony\Component\Config\FileLocator;
    2. use Symfony\Component\DependencyInjection\ContainerBuilder;
    3. use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
    4.  
    5. $containerBuilder = new ContainerBuilder();
    6. $loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__));
    7. $loader->load('services.php');

    You can now set up the newsletter_manager and services usingconfig files:

    • YAML
    1. parameters:
    2. # ...
    3. mailer.transport: sendmail
    4.  
    5. services:
    6. mailer:
    7. class: Mailer
    8. arguments: ['%mailer.transport%']
    9. newsletter_manager:
    10. class: NewsletterManager
    11. calls:
    12. - [setMailer, ['@mailer']]
    • XML
    1. <?xml version="1.0" encoding="UTF-8" ?>
    2. <container xmlns="http://symfony.com/schema/dic/services"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4.  
    5. <parameters>
    6. <!-- ... -->
    7. <parameter key="mailer.transport">sendmail</parameter>
    8. </parameters>
    9.  
    10. <services>
    11. <service id="mailer" class="Mailer">
    12. <argument>%mailer.transport%</argument>
    13. </service>
    14.  
    15. <service id="newsletter_manager" class="NewsletterManager">
    16. <call method="setMailer">
    17. <argument type="service" id="mailer"/>
    18. </call>
    19. </service>
    20. </services>
    21. </container>
    • PHP
    1. namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    2.  
    3. return function(ContainerConfigurator $configurator) {
    4. $configurator->parameters()
    5. // ...
    6. ->set('mailer.transport', 'sendmail')
    7. ;
    8.  
    9. $services = $configurator->services();
    10.  
    11. $services->set('mailer', 'Mailer')
    12. ->args(['%mailer.transport%'])
    13. ;
    14.  
    15. $services->set('newsletter_manager', 'NewsletterManager')
    16. ->call('setMailer', [ref('mailer')])
    17. ;
    18. };