Service Container

Screencast

スクリーンキャスト

Do you prefer video tutorials? Check out the Symfony Fundamentals screencast series.

ビデオチュートリアルが好きですか? Symfony Fundamentals スクリーンキャスト シリーズをチェックしてください。

Your application is full of useful objects: a "Mailer" object might help you send emails while another object might help you save things to the database. Almost everything that your app "does" is actually done by one of these objects. And each time you install a new bundle, you get access to even more!

あなたのアプリケーションは便利なオブジェクトでいっぱいです: "Mailer" オブジェクトはメールを送信するのに役立ち、別のオブジェクトはデータベースに何かを保存するのに役立ちます.あなたのアプリが「行う」ほとんどすべてのことは、実際にはこれらのオブジェクトの 1 つによって行われます.新しいバンドルをインストールすると、さらに多くの機能にアクセスできます!

In Symfony, these useful objects are called services and each service lives inside a very special object called the service container. The container allows you to centralize the way objects are constructed. It makes your life easier, promotes a strong architecture and is super fast!

Symfony では、これらの便利なオブジェクトはサービスと呼ばれ、各サービスはサービス コンテナーと呼ばれる非常に特別なオブジェクト内に存在します。コンテナを使用すると、オブジェクトの構築方法を一元化できます。それはあなたの生活を楽にし、強力なアーキテクチャを促進し、超高速です!

Fetching and using Services

The moment you start a Symfony app, your container already contains many services. These are like tools: waiting for you to take advantage of them. In your controller, you can "ask" for a service from the container by type-hinting an argument with the service's class or interface name. Want to log something? No problem:

Symfony アプリを起動した時点で、コンテナーには既に多くのサービスが含まれています。これらはツールのようなもので、ユーザーがそれらを利用するのを待っています。コントローラーでは、サービスのクラスまたはインターフェイス名を使用して引数を型ヒントすることにより、コンテナーからサービスを "要求" できます。何かを記録したいですか?問題ない:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Controller/ProductController.php
namespace App\Controller;

use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends AbstractController
{
    #[Route('/products')]
    public function list(LoggerInterface $logger): Response
    {
        $logger->info('Look, I just used a service!');

        // ...
    }
}

What other services are available? Find out by running:

他に利用できるサービスは?次を実行して確認します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ php bin/console debug:autowiring

  # this is just a *small* sample of the output...

  Autowirable Types
  =================

   The following classes & interfaces can be used as type-hints when autowiring:

   Describes a logger instance.
   Psr\Log\LoggerInterface (logger)

   Request stack that controls the lifecycle of requests.
   Symfony\Component\HttpFoundation\RequestStack (request_stack)

   RouterInterface is the interface that all Router classes must implement.
   Symfony\Component\Routing\RouterInterface (router.default)

   [...]

When you use these type-hints in your controller methods or inside your own services, Symfony will automatically pass you the service object matching that type.

これらの型ヒントをコントローラー メソッドまたは独自のサービス内で使用すると、Symfony はその型に一致するサービス オブジェクトを自動的に渡します。

Throughout the docs, you'll see how to use the many different services that live in the container.

ドキュメント全体を通して、コンテナー内に存在するさまざまなサービスの使用方法を確認できます。

Tip

ヒント

There are actually many more services in the container, and each service has a unique id in the container, like request_stack or router.default. For a full list, you can run php bin/console debug:container. But most of the time, you won't need to worry about this. See Service Container. See How to Debug the Service Container & List Services.

実際にはコンテナーにはさらに多くのサービスがあり、各サービスにはコンテナー内で request_stack や router.default などの一意の ID があります。完全なリストについては、php bin/console debug:container を実行できます。しかし、ほとんどの場合、これについて心配する必要はありません。 「サービス コンテナ」を参照してください。「サービス コンテナをデバッグしてサービスを一覧表示する方法」を参照してください。

Creating/Configuring Services in the Container

You can also organize your own code into services. For example, suppose you need to show your users a random, happy message. If you put this code in your controller, it can't be re-used. Instead, you decide to create a new class:

独自のコードをサービスに編成することもできます。たとえば、ランダムでハッピーなメッセージをユーザーに表示する必要があるとします。このコードをコントローラーに入れると、再利用できなくなります。代わりに、新しいクラスを作成することにします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Service/MessageGenerator.php
namespace App\Service;

class MessageGenerator
{
    public function getHappyMessage(): string
    {
        $messages = [
            'You did it! You updated the system! Amazing!',
            'That was one of the coolest updates I\'ve seen all day!',
            'Great work! Keep going!',
        ];

        $index = array_rand($messages);

        return $messages[$index];
    }
}

Congratulations! You've created your first service class! You can use it immediately inside your controller:

おめでとう!最初のサービス クラスが作成されました。コントローラー内ですぐに使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Controller/ProductController.php
use App\Service\MessageGenerator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends AbstractController
{
    #[Route('/products/new')]
    public function new(MessageGenerator $messageGenerator): Response
    {
        // thanks to the type-hint, the container will instantiate a
        // new MessageGenerator and pass it to you!
        // ...

        $message = $messageGenerator->getHappyMessage();
        $this->addFlash('success', $message);
        // ...
    }
}

When you ask for the MessageGenerator service, the container constructs a new MessageGenerator object and returns it (see sidebar below). But if you never ask for the service, it's never constructed: saving memory and speed. As a bonus, the MessageGenerator service is only created once: the same instance is returned each time you ask for it.

MessageGenerator サービスを要求すると、コンテナーは newMessageGenerator オブジェクトを作成して返します (下のサイドバーを参照)。しかし、サービスを要求しなければ、それは決して構築されません: メモリと速度を節約します。おまけに、MessageGenerator サービスは 1 回だけ作成されます。要求するたびに同じインスタンスが返されます。
services.yaml での自動サービス読み込み

The documentation assumes you're using the following service configuration, which is the default config for a new project:

このドキュメントでは、新しいプロジェクトのデフォルトの構成である次のサービス構成を使用していることを前提としています。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# config/services.yaml
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'

    # order is important in this file because service definitions
    # always *replace* previous ones; add your own service configuration below

    # ...

Tip

ヒント

The value of the resource and exclude options can be any valid glob pattern. The value of the exclude option can also be an array of glob patterns.

リソースおよび除外オプションの値は、任意の有効なグロブ パターンにすることができます。 exclude オプションの値は、glob パターンの配列にすることもできます。

Thanks to this configuration, you can automatically use any classes from the src/ directory as a service, without needing to manually configure it. Later, you'll learn more about this in Service Container.

この構成のおかげで、手動で構成する必要なく、src/ ディレクトリの任意のクラスをサービスとして自動的に使用できます。これについては、後でサービス コンテナーで詳しく説明します。

If you'd prefer to manually wire your service, that's totally possible: see Service Container.

サービスを手動で接続したい場合は、完全に可能です: サービス コンテナーを参照してください。

Limiting Services to a specific Symfony Environment

If you are using PHP 8.0 or later, you can use the #[When] PHP attribute to only register the class as a service in some environments:

PHP 8.0 以降を使用している場合は、 #[When] PHP 属性を使用して、一部の環境でのみクラスをサービスとして登録できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\DependencyInjection\Attribute\When;

// SomeClass is only registered in the "dev" environment

#[When(env: 'dev')]
class SomeClass
{
    // ...
}

// you can also apply more than one When attribute to the same class

#[When(env: 'dev')]
#[When(env: 'test')]
class AnotherClass
{
    // ...
}

Injecting Services/Config into a Service

What if you need to access the logger service from within MessageGenerator? No problem! Create a __construct() method with a $logger argument that has the LoggerInterface type-hint. Set this on a new $logger property and use it later:

MessageGenerator 内からロガー サービスにアクセスする必要がある場合はどうすればよいでしょうか?問題ありません。 LoggerInterface 型ヒントを持つ $logger 引数を持つ __construct() メソッドを作成します。これを新しい $logger プロパティに設定し、後で使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Service/MessageGenerator.php
namespace App\Service;

use Psr\Log\LoggerInterface;

class MessageGenerator
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function getHappyMessage(): string
    {
        $this->logger->info('About to find a happy message!');
        // ...
    }
}

That's it! The container will automatically know to pass the logger service when instantiating the MessageGenerator. How does it know to do this? Autowiring. The key is the LoggerInterface type-hint in your __construct() method and the autowire: true config in services.yaml. When you type-hint an argument, the container will automatically find the matching service. If it can't, you'll see a clear exception with a helpful suggestion.

それでおしまい!コンテナーは、MessageGenerator をインスタンス化するときに、ロガー サービスを渡すことを自動的に認識します。これを行うことをどのように知っていますか?自動配線。重要なのは、__construct() メソッドの LoggerInterfacetype-hint と autowire: true config inservices.yaml です。引数をタイプヒントすると、コンテナーは一致するサービスを自動的に見つけます。それができない場合は、役立つ提案とともに明確な例外が表示されます。

By the way, this method of adding dependencies to your __construct() method is called dependency injection.

ちなみに、この __construct() メソッドに依存関係を追加する方法は、依存関係の注入と呼ばれます。

How should you know to use LoggerInterface for the type-hint? You can either read the docs for whatever feature you're using, or get a list of autowireable type-hints by running:

タイプヒントに LoggerInterface を使用する方法を知っておく必要がありますか?使用している機能のドキュメントを読むか、次を実行して autowireabletype-hints のリストを取得できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ php bin/console debug:autowiring

  # this is just a *small* sample of the output...

  Describes a logger instance.
  Psr\Log\LoggerInterface (monolog.logger)

  Request stack that controls the lifecycle of requests.
  Symfony\Component\HttpFoundation\RequestStack (request_stack)

  RouterInterface is the interface that all Router classes must implement.
  Symfony\Component\Routing\RouterInterface (router.default)

  [...]

Handling Multiple Services

Suppose you also want to email a site administrator each time a site update is made. To do that, you create a new class:

また、サイトが更新されるたびにサイト管理者に電子メールを送信したいとします。そのためには、新しいクラスを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// src/Service/SiteUpdateManager.php
namespace App\Service;

use App\Service\MessageGenerator;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;

class SiteUpdateManager
{
    private $messageGenerator;
    private $mailer;

    public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer)
    {
        $this->messageGenerator = $messageGenerator;
        $this->mailer = $mailer;
    }

    public function notifyOfSiteUpdate(): bool
    {
        $happyMessage = $this->messageGenerator->getHappyMessage();

        $email = (new Email())
            ->from('admin@example.com')
            ->to('manager@example.com')
            ->subject('Site update just happened!')
            ->text('Someone just updated the site. We told them: '.$happyMessage);

        $this->mailer->send($email);

        // ...

        return true;
    }
}

This needs the MessageGenerator and the Mailer service. That's no problem, we ask them by type hinting their class and interface names! Now, this new service is ready to be used. In a controller, for example, you can type-hint the new SiteUpdateManager class and use it:

これには MessageGenerator と Mailer サービスが必要です。それは問題ありません。クラス名とインターフェース名をタイプヒントで尋ねます。これで、この新しいサービスを使用する準備が整いました。たとえば、コントローラーでは、新しい SiteUpdateManager クラスをタイプヒントして使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Controller/SiteController.php
namespace App\Controller;

use App\Service\SiteUpdateManager;
// ...

class SiteController extends AbstractController
{
    public function new(SiteUpdateManager $siteUpdateManager): Response
    {
        // ...

        if ($siteUpdateManager->notifyOfSiteUpdate()) {
            $this->addFlash('success', 'Notification mail was sent successfully.');
        }

        // ...
    }
}

Thanks to autowiring and your type-hints in __construct(), the container creates the SiteUpdateManager object and passes it the correct argument. In most cases, this works perfectly.

自動配線と __construct() の型ヒントのおかげで、コンテナーは SiteUpdateManager オブジェクトを作成し、それに正しい引数を渡します。ほとんどの場合、これは完全に機能します。

Manually Wiring Arguments

But there are a few cases when an argument to a service cannot be autowired. For example, suppose you want to make the admin email configurable:

ただし、サービスへの引数を自動配線できない場合がいくつかあります。たとえば、管理者の電子メールを構成可能にしたいとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// src/Service/SiteUpdateManager.php
  // ...

  class SiteUpdateManager
  {
      // ...
+    private $adminEmail;

-    public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer)
+    public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer, string $adminEmail)
      {
          // ...
+        $this->adminEmail = $adminEmail;
      }

      public function notifyOfSiteUpdate(): bool
      {
          // ...

          $email = (new Email())
              // ...
-            ->to('manager@example.com')
+            ->to($this->adminEmail)
              // ...
          ;
          // ...
      }
  }

If you make this change and refresh, you'll see an error:

この変更を行って更新すると、次のエラーが表示されます。

Cannot autowire service "App\Service\SiteUpdateManager": argument "$adminEmail" of method "__construct()" must have a type-hint or be given a value explicitly.

サービス "App\Service\SiteUpdateManager" を自動配線できません: メソッド "__construct()" の引数 "$adminEmail" には、型ヒントを指定するか、値を明示的に指定する必要があります。

That makes sense! There is no way that the container knows what value you want to pass here. No problem! In your configuration, you can explicitly set this argument:

それは理にかなっている!ここで渡したい値をコンテナが知る方法はありません。問題ない!構成では、この引数を明示的に設定できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
# config/services.yaml
services:
    # ... same as before

    # same as before
    App\:
        resource: '../src/'
        exclude: '../src/{DependencyInjection,Entity,Kernel.php}'

    # explicitly configure the service
    App\Service\SiteUpdateManager:
        arguments:
            $adminEmail: 'manager@example.com'

Thanks to this, the container will pass manager@example.com to the $adminEmail argument of __construct when creating the SiteUpdateManager service. The other arguments will still be autowired.

これにより、コンテナーは、SiteUpdateManager サービスを作成するときに、__construct の $adminEmail 引数に manager@example.com を渡します。他の引数は引き続き自動配線されます。

But, isn't this fragile? Fortunately, no! If you rename the $adminEmail argument to something else - e.g. $mainEmail - you will get a clear exception when you reload the next page (even if that page doesn't use this service).

でも、これって脆くないですか?幸いなことに、いいえ! $adminEmail 引数の名前を別のものに変更すると、たとえば、 $mainEmail - 次のページをリロードすると、明確な例外が発生します (そのページがこのサービスを使用していない場合でも)。

Service Parameters

In addition to holding service objects, the container also holds configuration, called parameters. The main article about Symfony configuration explains the configuration parameters in detail and shows all their types (string, boolean, array, binary and PHP constant parameters).

コンテナーは、サービス オブジェクトを保持するだけでなく、パラメーターと呼ばれる構成も保持します。 Symfony の構成に関するメインの記事では、構成パラメーターについて詳しく説明し、すべてのタイプ (文字列、ブール値、配列、バイナリー、および PHP 定数パラメーター) を示しています。

However, there is another type of parameter related to services. In YAML config, any string which starts with @ is considered as the ID of a service, instead of a regular string. In XML config, use the type="service" type for the parameter and in PHP config use the service() function:

ただし、サービスに関連する別の種類のパラメーターがあります。 YAML 構成では、@ で始まる文字列は、通常の文字列ではなく、サービスの ID と見なされます。 XML 構成では、パラメータに type="service" タイプを使用し、PHP 構成では service() 関数を使用します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
# config/services.yaml
services:
    App\Service\MessageGenerator:
        arguments:
            # this is not a string, but a reference to a service called 'logger'
            - '@logger'

            # if the value of a string argument starts with '@', you need to escape
            # it by adding another '@' so Symfony doesn't consider it a service
            # the following example would be parsed as the string '@securepassword'
            # - '@@securepassword'

Working with container parameters is straightforward using the container's accessor methods for parameters:

コンテナー パラメーターの操作は、パラメーターのコンテナーのアクセサー メソッドを使用して簡単に行うことができます。
1
2
3
4
5
6
7
8
// checks if a parameter is defined (parameter names are case-sensitive)
$container->hasParameter('mailer.transport');

// gets value of a parameter
$container->getParameter('mailer.transport');

// adds a new parameter
$container->setParameter('mailer.transport', 'sendmail');

Caution

注意

The used . notation is a Symfony convention to make parameters easier to read. Parameters are flat key-value elements, they can't be organized into a nested array

中古品 。表記法は、パラメーターを読みやすくするための Symfony の規則です。パラメータはフラットなキーと値の要素であり、ネストされた配列に編成することはできません

Note

ノート

You can only set a parameter before the container is compiled, not at run-time. To learn more about compiling the container see Compiling the Container.

パラメーターは、実行時ではなく、コンテナーがコンパイルされる前にのみ設定できます。コンテナーのコンパイルの詳細については、コンテナーのコンパイルを参照してください。

Choose a Specific Service

The MessageGenerator service created earlier requires a LoggerInterface argument:

前に作成した MessageGenerator サービスには、LoggerInterface 引数が必要です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Service/MessageGenerator.php
namespace App\Service;

use Psr\Log\LoggerInterface;

class MessageGenerator
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
    // ...
}

However, there are multiple services in the container that implement LoggerInterface, such as logger, monolog.logger.request, monolog.logger.php, etc. How does the container know which one to use?

ただし、コンテナーには、logger、monolog.logger.request、monolog.logger.php など、LoggerInterface を実装する複数のサービスがあります。コンテナーはどのサービスを使用するかをどのように認識しますか?

In these situations, the container is usually configured to automatically choose one of the services - logger in this case (read more about why in Defining Services Dependencies Automatically (Autowiring)). But, you can control this and pass in a different logger:

このような状況では、コンテナーは通常、サービスの 1 つ (この場合はロガー) を自動的に選択するように構成されます (理由については、サービスの依存関係を自動的に定義する (自動配線) を参照してください)。ただし、これを制御して、別のロガーを渡すことができます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
# config/services.yaml
services:
    # ... same code as before

    # explicitly configure the service
    App\Service\MessageGenerator:
        arguments:
            # the '@' symbol is important: that's what tells the container
            # you want to pass the *service* whose id is 'monolog.logger.request',
            # and not just the *string* 'monolog.logger.request'
            $logger: '@monolog.logger.request'

This tells the container that the $logger argument to __construct should use service whose id is monolog.logger.request.

これは、コンテナに、__construct への $logger 引数が ID が monolog.logger.request であるサービスを使用する必要があることを伝えます。

For a full list of all possible services in the container, run:

コンテナー内のすべての可能なサービスの完全なリストについては、次を実行します。
1
$ php bin/console debug:container

Binding Arguments by Name or Type

You can also use the bind keyword to bind specific arguments by name or type:

bind キーワードを使用して、特定の引数を名前または型でバインドすることもできます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# config/services.yaml
services:
    _defaults:
        bind:
            # pass this value to any $adminEmail argument for any service
            # that's defined in this file (including controller arguments)
            $adminEmail: 'manager@example.com'

            # pass this service to any $requestLogger argument for any
            # service that's defined in this file
            $requestLogger: '@monolog.logger.request'

            # pass this service for any LoggerInterface type-hint for any
            # service that's defined in this file
            Psr\Log\LoggerInterface: '@monolog.logger.request'

            # optionally you can define both the name and type of the argument to match
            string $adminEmail: 'manager@example.com'
            Psr\Log\LoggerInterface $requestLogger: '@monolog.logger.request'
            iterable $rules: !tagged_iterator app.foo.rule

    # ...

By putting the bind key under _defaults, you can specify the value of any argument for any service defined in this file! You can bind arguments by name (e.g. $adminEmail), by type (e.g. Psr\Log\LoggerInterface) or both (e.g. Psr\Log\LoggerInterface $requestLogger).

バインド キーを _defaults の下に置くことで、このファイルで定義された任意のサービスに対して任意の引数の値を指定できます。引数は、名前 (例: $adminEmail)、タイプ (例: Psr\Log\LoggerInterface)、またはその両方 (例: Psr\Log\LoggerInterface $requestLogger) でバインドできます。

The bind config can also be applied to specific services or when loading many services at once (i.e. Service Container).

バインド構成は、特定のサービスに適用することも、一度に多くのサービスをロードする場合にも適用できます (つまり、サービス コンテナー)。

The autowire Option

Above, the services.yaml file has autowire: true in the _defaults section so that it applies to all services defined in that file. With this setting, you're able to type-hint arguments in the __construct() method of your services and the container will automatically pass you the correct arguments. This entire entry has been written around autowiring.

上記の services.yaml ファイルには autowire: true が _defaults セクションに含まれているため、そのファイルで定義されているすべてのサービスに適用されます。この設定により、サービスの __construct() メソッドで引数を型ヒントすることができ、コンテナは正しい引数を自動的に渡します。このエントリ全体は、自動配線を中心に書かれています。

For more details about autowiring, check out Defining Services Dependencies Automatically (Autowiring).

自動配線の詳細については、サービスの依存関係を自動的に定義する (自動配線) を参照してください。

The autoconfigure Option

Above, the services.yaml file has autoconfigure: true in the _defaults section so that it applies to all services defined in that file. With this setting, the container will automatically apply certain configuration to your services, based on your service's class. This is mostly used to auto-tag your services.

上記の services.yaml ファイルには autoconfigure: true が _defaults セクションに含まれているため、そのファイルで定義されているすべてのサービスに適用されます。この設定により、コンテナーは、サービスのクラスに基づいて、特定の構成をサービスに自動的に適用します。これは主にサービスの自動タグ付けに使用されます。

For example, to create a Twig extension, you need to create a class, register it as a service, and tag it with twig.extension.

たとえば、Twig 拡張機能を作成するには、クラスを作成し、それをサービスとして登録して、twig.extension でタグ付けする必要があります。

But, with autoconfigure: true, you don't need the tag. In fact, if you're using the default services.yaml config, you don't need to do anything: the service will be automatically loaded. Then, autoconfigure will add the twig.extension tag for you, because your class implements Twig\Extension\ExtensionInterface. And thanks to autowire, you can even add constructor arguments without any configuration.

ただし、autoconfigure: true を使用すると、タグは必要ありません。実際、デフォルトの services.yaml 構成を使用している場合は、何もする必要はありません。サービスは自動的に読み込まれます。次に、クラスが Twig\Extension\ExtensionInterface を実装しているため、autoconfigure は twig.extension タグを追加します。また、autowire のおかげで、構成なしでコンストラクター引数を追加することもできます。

Linting Service Definitions

The lint:container command checks that the arguments injected into services match their type declarations. It's useful to run it before deploying your application to production (e.g. in your continuous integration server):

lint:container コマンドは、サービスに挿入された引数が型宣言と一致することを確認します。アプリケーションを本番環境 (継続的インテグレーション サーバーなど) にデプロイする前に実行すると便利です。
1
$ php bin/console lint:container

Checking the types of all service arguments whenever the container is compiled can hurt performance. That's why this type checking is implemented in a compiler pass called CheckTypeDeclarationsPass which is disabled by default and enabled only when executing the lint:container command. If you don't mind the performance loss, enable the compiler pass in your application.

コンテナーがコンパイルされるたびにすべてのサービス引数の型をチェックすると、パフォーマンスが低下する可能性があります。そのため、この型チェックは CheckTypeDeclarationsPass というコンパイラ パスに実装されています。このコンパイラ パスはデフォルトで無効になっており、lint:container コマンドを実行するときのみ有効になっています。パフォーマンスの低下を気にしない場合は、アプリケーションでコンパイラ パスを有効にします。

Public Versus Private Services

Every service defined is private by default. When a service is private, you cannot access it directly from the container using $container->get(). As a best practice, you should only create private services and you should fetch services using dependency injection instead of using $container->get().

定義されたすべてのサービスは、デフォルトでプライベートです。サービスがプライベートの場合、$container->get() を使用してコンテナーから直接アクセスすることはできません。ベスト プラクティスとして、プライベート サービスのみを作成し、$container->get() を使用する代わりに依存性注入を使用してサービスをフェッチする必要があります。

If you need to fetch services lazily, instead of using public services you should consider using a service locator.

サービスを遅延して取得する必要がある場合は、パブリック サービスを使用する代わりに、サービス ロケーターの使用を検討する必要があります。

But, if you do need to make a service public, override the public setting:

ただし、サービスを公開する必要がある場合は、public 設定をオーバーライドします。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
# config/services.yaml
services:
    # ... same code as before

    # explicitly configure the service
    App\Service\PublicService:
        public: true

Importing Many Services at once with resource

You've already seen that you can import many services at once by using the resource key. For example, the default Symfony configuration contains this:

リソースキーを使用すると、一度に多数のサービスをインポートできることは既に説明しました。たとえば、デフォルトの Symfony 構成には次のものが含まれます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
# config/services.yaml
services:
    # ... same as before

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude: '../src/{DependencyInjection,Entity,Kernel.php}'

Tip

ヒント

The value of the resource and exclude options can be any valid glob pattern.

リソースおよび除外オプションの値は、任意の有効なグロブ パターンにすることができます。

This can be used to quickly make many classes available as services and apply some default configuration. The id of each service is its fully-qualified class name. You can override any service that's imported by using its id (class name) below (e.g. see Service Container). If you override a service, none of the options (e.g. public) are inherited from the import (but the overridden service does still inherit from _defaults).

これを使用して、多くのクラスをサービスとして迅速に利用可能にし、いくつかのデフォルト構成を適用できます。各サービスの ID は、その完全修飾クラス名です。以下の ID (クラス名) を使用して、インポートされたサービスをオーバーライドできます (例: サービス コンテナーを参照)。サービスをオーバーライドすると、どのオプション (パブリックなど) もインポートから継承されません (ただし、オーバーライドされたサービスは引き続き _defaults から継承されます)。

You can also exclude certain paths. This is optional, but will slightly increase performance in the dev environment: excluded paths are not tracked and so modifying them will not cause the container to be rebuilt.

特定のパスを除外することもできます。これはオプションですが、開発環境でのパフォーマンスがわずかに向上します。除外されたパスは追跡されないため、それらを変更してもコンテナーは再構築されません。

Note

ノート

Wait, does this mean that every class in src/ is registered as a service? Even model classes? Actually, no. As long as you keep your imported services as private, all classes in src/ that are not explicitly used as services are automatically removed from the final container. In reality, the import means that all classes are "available to be used as services" without needing to be manually configured.

ちょっと待って、これは src/ のすべてのクラスがサービスとして登録されているということですか?モデルクラスでも?実は違う。インポートしたサービスをプライベートとして保持している限り、サービスとして明示的に使用されていない src/ 内のすべてのクラスは、最終的なコンテナーから自動的に削除されます。実際には、インポートとは、手動で構成する必要なく、すべてのクラスが「サービスとして使用できる」ことを意味します。

Multiple Service Definitions Using the Same Namespace

If you define services using the YAML config format, the PHP namespace is used as the key of each configuration, so you can't define different service configs for classes under the same namespace:

YAML 構成形式を使用してサービスを定義する場合、PHP 名前空間が各構成のキーとして使用されるため、同じ名前空間でクラスに異なるサービス構成を定義することはできません。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
# config/services.yaml
services:
    App\Domain\:
        resource: '../src/Domain/*'
        # ...

In order to have multiple definitions, add the namespace option and use any unique string as the key of each service config:

複数の定義を持つには、名前空間オプションを追加し、各サービス構成のキーとして一意の文字列を使用します。
1
2
3
4
5
6
7
8
9
10
11
# config/services.yaml
services:
    command_handlers:
        namespace: App\Domain\
        resource: '../src/Domain/*/CommandHandler'
        tags: [command_handler]

    event_subscribers:
        namespace: App\Domain\
        resource: '../src/Domain/*/EventSubscriber'
        tags: [event_subscriber]

Explicitly Configuring Services and Arguments

Loading services automatically and autowiring are optional. And even if you use them, there may be some cases where you want to manually wire a service. For example, suppose that you want to register 2 services for the SiteUpdateManager class - each with a different admin email. In this case, each needs to have a unique service id:

サービスの自動ロードとオートワイヤーはオプションです。また、それらを使用する場合でも、手動でサービスを配線したい場合があります。たとえば、SiteUpdateManager クラスに 2 つのサービスを登録するとします。それぞれに異なる管理者の電子メールが割り当てられます。この場合、それぞれに一意のサービス ID が必要です。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# config/services.yaml
services:
    # ...

    # this is the service's id
    site_update_manager.superadmin:
        class: App\Service\SiteUpdateManager
        # you CAN still use autowiring: we just want to show what it looks like without
        autowire: false
        # manually wire all arguments
        arguments:
            - '@App\Service\MessageGenerator'
            - '@mailer'
            - 'superadmin@example.com'

    site_update_manager.normal_users:
        class: App\Service\SiteUpdateManager
        autowire: false
        arguments:
            - '@App\Service\MessageGenerator'
            - '@mailer'
            - 'contact@example.com'

    # Create an alias, so that - by default - if you type-hint SiteUpdateManager,
    # the site_update_manager.superadmin will be used
    App\Service\SiteUpdateManager: '@site_update_manager.superadmin'

In this case, two services are registered: site_update_manager.superadmin and site_update_manager.normal_users. Thanks to the alias, if you type-hint SiteUpdateManager the first (site_update_manager.superadmin) will be passed. If you want to pass the second, you'll need to manually wire the service.

この場合、site_update_manager.superadmin と site_update_manager.normal_users の 2 つのサービスが登録されています。エイリアスのおかげで、hintSiteUpdateManager と入力すると、最初の (site_update_manager.superadmin) が渡されます。2 番目を渡したい場合は、サービスを手動で接続する必要があります。

Caution

注意

If you do not create the alias and are loading all services from src/, then three services have been created (the automatic service + your two services) and the automatically loaded service will be passed - by default - when you type-hint SiteUpdateManager. That's why creating the alias is a good idea.

エイリアスを作成せず、src/ からすべてのサービスをロードしている場合は、3 つのサービス (自動サービス + 2 つのサービス) が作成されており、hintSiteUpdateManager と入力すると、デフォルトで、自動的にロードされたサービスが渡されます。そのため、エイリアスを作成することをお勧めします。

Learn more