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.

このコンポーネントを Symfony アプリケーションの外部にインストールする場合は、Composer が提供するクラス自動ロード メカニズムを有効にするために、コード内に vendor/autoload.php ファイルを必要とする必要があります。詳細については、この記事をお読みください。

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.

この記事では、DependencyInjection 機能を任意の PHP アプリケーションで独立したコンポーネントとして使用する方法について説明します。サービスコンテナの記事を読んで、Symfony アプリケーションでそれを使用する方法を学んでください。

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

次の Mailer のようなクラスをサービスとして利用できるようにする場合があります。
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:

どのメール トランスポートを選択したかは、他のサービスが知る必要があるものかもしれません。複数の場所で変更する必要がないようにするには、コンテナー内でパラメーターを作成し、このパラメーターを Mailer サービスのコンストラクター引数として参照します。
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:

メーラー サービスがコンテナー内にあるので、それを他のクラスの依存関係として注入できます。次のような NewsletterManager クラスがある場合:
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:

Newsletter_manager サービスを定義するとき、メーラー サービスはまだ存在しません。 Reference クラスを使用して、コンテナがニュースレター マネージャを初期化するときにメーラー サービスを挿入するように指示します。
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:

NewsletterManager が Mailer を必要とせず、injectingit がオプションでしかない場合は、代わりにセッター注入を使用できます。
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:

Mailer を NewsletterManager に挿入しないことを選択できるようになりました。必要に応じて、コンテナーは setter メソッドを呼び出すことができます。
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:

次に、次のようにコンテナからnewsletter_managerサービスを取得できます。
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.

コンテナから直接サービスを取得できますが、これを最小限に抑えるのが最善です。たとえば、NewsletterManager では、メーラー サービスをコンテナーに要求するのではなく、注入しました。コンテナーを注入し、そこからメーラー サービスを取得することもできますが、この特定のコンテナーに結び付けられて、別の場所でクラスを再利用することが難しくなります。 .

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.

上記のように PHP を使用してサービスをセットアップするだけでなく、構成ファイルを使用することもできます。これにより、上記の例のように PHP を使用してサービスを定義するのではなく、XML または YAML を使用してサービスの定義を記述することができます。最小のアプリケーション以外では、サービス定義を 1 つまたは複数の構成ファイルに移動して整理するのが理にかなっています。これを行うには、Config コンポーネントもインストールする必要があります。

Loading an XML config file:

XML 構成ファイルのロード:
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:

YAML 構成ファイルのロード:
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.

YAML 構成ファイルをロードする場合は、YAML コンポーネントもインストールする必要があります。

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:

アプリケーションが型にはまらないファイル拡張子を使用している場合 (たとえば、XML ファイルの拡張子が .config の場合)、load() メソッドの 2 番目のオプション パラメータとしてファイル タイプを渡すことができます。
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:

PHP を使用してサービスを作成する場合は、これを別の構成ファイルに移動して、同様の方法でロードできます。
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:

構成ファイルを使用して、newsletter_manager およびメーラー サービスをセットアップできるようになりました。
  • 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