The DependencyInjection Component ¶
The DependencyInjection component implements a PSR-11 compatible service container that allows you to standardize and centralize the way objects are constructed in your application.
DependencyInjection コンポーネントは、アプリケーションでオブジェクトを構築する方法を標準化および一元化できる PSR-11 互換のサービス コンテナーを実装します。
For an introduction to Dependency Injection and service containers see Service Container.
Installation ¶
1 |
$ composer require symfony/dependency-injection
|
Note
If you install this component outside of a Symfony application, you must
require the vendor/autoload.php
file in your code to enable the class
autoloading mechanism provided by Composer. Read
this article for more details.
Basic Usage ¶
See also
This article explains how to use the DependencyInjection features as an independent component in any PHP application. Read the Service Container article to learn about how to use it in Symfony applications.
You might have a class like the following Mailer
that
you want to make available as a service:
1 2 3 4 5 6 7 8 9 10 11 |
class Mailer
{
private $transport;
public function __construct()
{
$this->transport = 'sendmail';
}
// ...
}
|
You can register this in the container as a service:
1 2 3 4 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
$containerBuilder->register('mailer', 'Mailer');
|
An improvement to the class to make it more flexible would be to allow
the container to set the transport
used. If you change the class
so this is passed into the constructor:
1 2 3 4 5 6 7 8 9 10 11 |
class Mailer
{
private $transport;
public function __construct($transport)
{
$this->transport = $transport;
}
// ...
}
|
Then you can set the choice of transport in the container:
1 2 3 4 5 6 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
$containerBuilder
->register('mailer', 'Mailer')
->addArgument('sendmail');
|
This class is now much more flexible as you have separated the choice of transport out of the implementation and into the container.
Which mail transport you have chosen may be something other services need
to know about. You can avoid having to change it in multiple places by making
it a parameter in the container and then referring to this parameter for
the Mailer
service's constructor argument:
1 2 3 4 5 6 7 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
$containerBuilder->setParameter('mailer.transport', 'sendmail');
$containerBuilder
->register('mailer', 'Mailer')
->addArgument('%mailer.transport%');
|
Now that the mailer
service is in the container you can inject it as
a dependency of other classes. If you have a NewsletterManager
class
like this:
1 2 3 4 5 6 7 8 9 10 11 |
class NewsletterManager
{
private $mailer;
public function __construct(\Mailer $mailer)
{
$this->mailer = $mailer;
}
// ...
}
|
When defining the newsletter_manager
service, the mailer
service does
not exist yet. Use the Reference
class to tell the container to inject the
mailer
service when it initializes the newsletter manager:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
$containerBuilder = new ContainerBuilder();
$containerBuilder->setParameter('mailer.transport', 'sendmail');
$containerBuilder
->register('mailer', 'Mailer')
->addArgument('%mailer.transport%');
$containerBuilder
->register('newsletter_manager', 'NewsletterManager')
->addArgument(new Reference('mailer'));
|
If the NewsletterManager
did not require the Mailer
and injecting
it was only optional then you could use setter injection instead:
1 2 3 4 5 6 7 8 9 10 11 |
class NewsletterManager
{
private $mailer;
public function setMailer(\Mailer $mailer)
{
$this->mailer = $mailer;
}
// ...
}
|
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 2 3 4 5 6 7 8 9 10 11 12 13 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
$containerBuilder = new ContainerBuilder();
$containerBuilder->setParameter('mailer.transport', 'sendmail');
$containerBuilder
->register('mailer', 'Mailer')
->addArgument('%mailer.transport%');
$containerBuilder
->register('newsletter_manager', 'NewsletterManager')
->addMethodCall('setMailer', [new Reference('mailer')]);
|
You could then get your newsletter_manager
service from the container
like this:
1 2 3 4 5 6 7 |
use Symfony\Component\DependencyInjection\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
// ...
$newsletterManager = $containerBuilder->get('newsletter_manager');
|
Avoiding your Code Becoming Dependent on the Container ¶
Whilst you can retrieve services from the container directly it is best
to minimize this. For example, in the NewsletterManager
you injected
the mailer
service in rather than asking for it from the container.
You could have injected the container in and retrieved the mailer
service
from it but it would then be tied to this particular container making it
difficult to reuse the class elsewhere.
You will need to get a service from the container at some point but this should be as few times as possible at the entry point to your application.
Setting up the Container with Configuration Files ¶
As well as setting up the services using PHP as above you can also use configuration files. This allows you to use XML or YAML to write the definitions for the services rather than using PHP to define the services as in the above examples. In anything but the smallest applications it makes sense to organize the service definitions by moving them into one or more configuration files. To do this you also need to install the Config component.
Loading an XML config file:
1 2 3 4 5 6 7 |
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
$containerBuilder = new ContainerBuilder();
$loader = new XmlFileLoader($containerBuilder, new FileLocator(__DIR__));
$loader->load('services.xml');
|
Loading a YAML config file:
1 2 3 4 5 6 7 |
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
$containerBuilder = new ContainerBuilder();
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__));
$loader->load('services.yaml');
|
Note
If you want to load YAML config files then you will also need to install the Yaml component.
Tip
If your application uses unconventional file extensions (for example, your
XML files have a .config
extension) you can pass the file type as the
second 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 this into a separate config file and load it in a similar way:
1 2 3 4 5 6 7 |
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
$containerBuilder = new ContainerBuilder();
$loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__));
$loader->load('services.php');
|
You can now set up the newsletter_manager
and mailer
services using
config files:
-
YAML
YAML
-
XML
XML
-
PHP
PHP
1 2 3 4 5 6 7 8 9 10 11 12 |
parameters:
# ...
mailer.transport: sendmail
services:
mailer:
class: Mailer
arguments: ['%mailer.transport%']
newsletter_manager:
class: NewsletterManager
calls:
- [setMailer, ['@mailer']]
|
Learn More ¶
- Compiling the Containerコンテナのコンパイル
- Container Building Workflowコンテナ構築のワークフロー
- How to Create Service Aliases and Mark Services as Privateサービス エイリアスを作成し、サービスをプライベートとしてマークする方法
- Defining Services Dependencies Automatically (Autowiring)サービスの依存関係を自動的に定義する (オートワイヤー)
- Service Method Calls and Setter Injectionサービス メソッドの呼び出しとセッター インジェクション
- How to Work with Compiler Passesコンパイラ パスの使用方法
- How to Configure a Service with a ConfiguratorConfigurator を使用してサービスを構成する方法
- How to Debug the Service Container & List Servicesサービス コンテナとリスト サービスをデバッグする方法
- How to work with Service Definition Objectsサービス定義オブジェクトの操作方法
- How to Inject Values Based on Complex Expressions複雑な式に基づいて値を挿入する方法
- Using a Factory to Create Servicesファクトリを使用してサービスを作成する
- How to Import Configuration Files/Resources構成ファイル/リソースをインポートする方法
- Types of Injection注射の種類
- Lazy Services遅延サービス
- How to Make Service Arguments/References Optionalサービスの引数/参照をオプションにする方法
- How to Manage Common Dependencies with Parent Services親サービスで共通の依存関係を管理する方法
- How to Retrieve the Request from the Service Containerサービス コンテナからリクエストを取得する方法
- How to Decorate Servicesサービスの装飾方法
- Service Subscribers & Locatorsサービスのサブスクライバーとロケーター
- How to Define Non Shared Services非共有サービスを定義する方法
- How to Inject Instances into the Containerコンテナにインスタンスを注入する方法
- How to Work with Service Tagsサービス タグの使用方法