Defining Services Dependencies Automatically (Autowiring)

Autowiring allows you to manage services in the container with minimal configuration. It reads the type-hints on your constructor (or other methods) and automatically passes the correct services to each method. Symfony's autowiring is designed to be predictable: if it is not absolutely clear which dependency should be passed, you'll see an actionable exception.

自動配線により、最小限の構成でコンテナー内のサービスを管理できます。コンストラクター (または他のメソッド) の型ヒントを読み取り、正しいサービスを各メソッドに自動的に渡します。 symfony のオートワイヤリングは、予測できるように設計されています。どの依存関係を渡す必要があるかが完全に明確でない場合、アクション可能な例外が表示されます。

Tip

ヒント

Thanks to Symfony's compiled container, there is no runtime overhead for using autowiring.

Symfony のコンパイル済みコンテナーのおかげで、autowiring を使用するための実行時のオーバーヘッドはありません。

An Autowiring Example

Imagine you're building an API to publish statuses on a Twitter feed, obfuscated with ROT13, a fun encoder that shifts all characters 13 letters forward in the alphabet.

Twitter フィードでステータスを公開する API を構築していると想像してください。ROT13 は、すべての文字をアルファベットで 13 文字前方にシフトする楽しいエンコーダーです。

Start by creating a ROT13 transformer class:

ROT13 トランスフォーマー クラスを作成することから始めます。
1
2
3
4
5
6
7
8
9
10
// src/Util/Rot13Transformer.php
namespace App\Util;

class Rot13Transformer
{
    public function transform(string $value): string
    {
        return str_rot13($value);
    }
}

And now a Twitter client using this transformer:

次に、このトランスフォーマーを使用する Twitter クライアント:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/Service/TwitterClient.php
namespace App\Service;

use App\Util\Rot13Transformer;
// ...

class TwitterClient
{
    private $transformer;

    public function __construct(Rot13Transformer $transformer)
    {
        $this->transformer = $transformer;
    }

    public function tweet(User $user, string $key, string $status): void
    {
        $transformedStatus = $this->transformer->transform($status);

        // ... connect to Twitter and send the encoded status
    }
}

If you're using the default services.yaml configuration, both classes are automatically registered as services and configured to be autowired. This means you can use them immediately without any configuration.

デフォルトの services.yaml 構成を使用している場合、両方のクラスが自動的にサービスとして登録され、自動配線されるように構成されます。つまり、構成なしですぐに使用できます。

However, to understand autowiring better, the following examples explicitly configure both services:

ただし、自動配線をよりよく理解するために、次の例では両方のサービスを明示的に構成しています。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
# config/services.yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true
    # ...

    App\Service\TwitterClient:
        # redundant thanks to _defaults, but value is overridable on each service
        autowire: true

    App\Util\Rot13Transformer:
        autowire: true

Now, you can use the TwitterClient service immediately in a controller:

これで、コントローラーで TwitterClient サービスをすぐに使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Controller/DefaultController.php
namespace App\Controller;

use App\Service\TwitterClient;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController
{
    #[Route('/tweet')]
    public function tweet(TwitterClient $twitterClient, Request $request): Response
    {
        // fetch $user, $key, $status from the POST'ed data

        $twitterClient->tweet($user, $key, $status);

        // ...
    }
}

This works automatically! The container knows to pass the Rot13Transformer service as the first argument when creating the TwitterClient service.

これは自動的に機能します!コンテナーは、TwitterClient サービスを作成するときに、最初の引数として Rot13Transformer サービスを渡すことを認識しています。

Autowiring Logic Explained

Autowiring works by reading the Rot13Transformer type-hint in TwitterClient:

自動配線は、TwitterClient の Rot13Transformer タイプヒントを読み取ることで機能します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Service/TwitterClient.php
namespace App\Service;

// ...
use App\Util\Rot13Transformer;

class TwitterClient
{
    // ...

    public function __construct(Rot13Transformer $transformer)
    {
        $this->transformer = $transformer;
    }
}

The autowiring system looks for a service whose id exactly matches the type-hint: so App\Util\Rot13Transformer. In this case, that exists! When you configured the Rot13Transformer service, you used its fully-qualified class name as its id. Autowiring isn't magic: it looks for a service whose id matches the type-hint. If you load services automatically, each service's id is its class name.

自動配線システムは、id が type-hint:so App\Util\Rot13Transformer と正確に一致するサービスを探します。この場合、それは存在します! Rot13Transformer サービスを構成したときに、その完全修飾クラス名を ID として使用しました。 Autowiring は魔法ではありません。id が type-hint と一致するサービスを探します。サービスを自動的にロードする場合、各サービスの id はそのクラス名です。

If there is not a service whose id exactly matches the type, a clear exception will be thrown.

ID がタイプと正確に一致するサービスがない場合、明確な例外がスローされます。

Autowiring is a great way to automate configuration, and Symfony tries to be as predictable and as clear as possible.

自動配線は構成を自動化する優れた方法であり、Symfony は可能な限り予測可能で明確になるように努めています。

Using Aliases to Enable Autowiring

The main way to configure autowiring is to create a service whose id exactly matches its class. In the previous example, the service's id is App\Util\Rot13Transformer, which allows us to autowire this type automatically.

自動配線を構成する主な方法は、id がそのクラスと正確に一致するサービスを作成することです。前の例では、サービスの ID は App\Util\Rot13Transformer であり、このタイプを自動的にオートワイヤーできます。

This can also be accomplished using an alias. Suppose that for some reason, the id of the service was instead app.rot13.transformer. In this case, any arguments type-hinted with the class name (App\Util\Rot13Transformer) can no longer be autowired.

これはエイリアスを使用して行うこともできます。何らかの理由で、サービスの ID が代わりに app.rot13.transformer だったとします。この場合、クラス名 (App\Util\Rot13Transformer) で型ヒントされた引数は、オートワイヤーできなくなります。

No problem! To fix this, you can create a service whose id matches the class by adding a service alias:

問題ない!これを修正するには、サービス エイリアスを追加して、ID がクラスと一致するサービスを作成します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
# config/services.yaml
services:
    # ...

    # the id is not a class, so it won't be used for autowiring
    app.rot13.transformer:
        class: App\Util\Rot13Transformer
        # ...

    # but this fixes it!
    # the ``app.rot13.transformer`` service will be injected when
    # an ``App\Util\Rot13Transformer`` type-hint is detected
    App\Util\Rot13Transformer: '@app.rot13.transformer'

This creates a service "alias", whose id is App\Util\Rot13Transformer. Thanks to this, autowiring sees this and uses it whenever the Rot13Transformer class is type-hinted.

これにより、ID が App\Util\Rot13Transformer であるサービス「エイリアス」が作成されます。これにより、オートワイヤリングはこれを認識し、Rot13Transformerclass がタイプ ヒンティングされるたびにそれを使用します。

Tip

ヒント

Aliases are used by the core bundles to allow services to be autowired. For example, MonologBundle creates a service whose id is logger. But it also adds an alias: Psr\Log\LoggerInterface that points to the logger service. This is why arguments type-hinted with Psr\Log\LoggerInterface can be autowired.

コア バンドルはエイリアスを使用して、サービスを自動接続できるようにします。たとえば、MonologBu​​ndle は、id が logger であるサービスを作成します。しかし、ロガー サービスを指すエイリアス: Psr\Log\LoggerInterface も追加します。

Working with Interfaces

You might also find yourself type-hinting abstractions (e.g. interfaces) instead of concrete classes as it replaces your dependencies with other objects.

また、依存関係を他のオブジェクトに置き換えるため、具体的なクラスではなく、型ヒントの抽象化 (インターフェイスなど) を使用していることに気付くかもしれません。

To follow this best practice, suppose you decide to create a TransformerInterface:

このベスト プラクティスに従うために、TransformerInterface を作成するとします。
1
2
3
4
5
6
7
// src/Util/TransformerInterface.php
namespace App\Util;

interface TransformerInterface
{
    public function transform(string $value): string;
}

Then, you update Rot13Transformer to implement it:

次に、Rot13Transformer を更新して実装します。
1
2
3
4
5
// ...
class Rot13Transformer implements TransformerInterface
{
    // ...
}

Now that you have an interface, you should use this as your type-hint:

インターフェースができたので、これを型ヒントとして使用する必要があります。
1
2
3
4
5
6
7
8
9
class TwitterClient
{
    public function __construct(TransformerInterface $transformer)
    {
        // ...
    }

    // ...
}

But now, the type-hint (App\Util\TransformerInterface) no longer matches the id of the service (App\Util\Rot13Transformer). This means that the argument can no longer be autowired.

しかし現在、タイプヒント (App\Util\TransformerInterface) はサービスの ID (App\Util\Rot13Transformer) と一致しなくなりました。これは、引数をオートワイヤーできなくなったことを意味します。

To fix that, add an alias:

これを修正するには、エイリアスを追加します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
# config/services.yaml
services:
    # ...

    App\Util\Rot13Transformer: ~

    # the ``App\Util\Rot13Transformer`` service will be injected when
    # an ``App\Util\TransformerInterface`` type-hint is detected
    App\Util\TransformerInterface: '@App\Util\Rot13Transformer'

Thanks to the App\Util\TransformerInterface alias, the autowiring subsystem knows that the App\Util\Rot13Transformer service should be injected when dealing with the TransformerInterface.

App\Util\TransformerInterface エイリアスのおかげで、自動配線サブシステムは、TransformerInterface を処理するときに App\Util\Rot13Transformer サービスを注入する必要があることを認識します。

Tip

ヒント

When using a service definition prototype, if only one service is discovered that implements an interface, configuring the alias is not mandatory and Symfony will automatically create one.

サービス定義プロトタイプを使用する場合、インターフェースを実装するサービスが 1 つだけ検出された場合、エイリアスの設定は必須ではなく、Symfony が自動的にエイリアスを作成します。

Dealing with Multiple Implementations of the Same Type

Suppose you create a second class - UppercaseTransformer that implements TransformerInterface:

TransformerInterface を実装する 2 番目のクラス UppercaseTransformer を作成するとします。
1
2
3
4
5
6
7
8
9
10
// src/Util/UppercaseTransformer.php
namespace App\Util;

class UppercaseTransformer implements TransformerInterface
{
    public function transform(string $value): string
    {
        return strtoupper($value);
    }
}

If you register this as a service, you now have two services that implement the App\Util\TransformerInterface type. Autowiring subsystem can not decide which one to use. Remember, autowiring isn't magic; it looks for a service whose id matches the type-hint. So you need to choose one by creating an alias from the type to the correct service id (see Defining Services Dependencies Automatically (Autowiring)). Additionally, you can define several named autowiring aliases if you want to use one implementation in some cases, and another implementation in some other cases.

これをサービスとして登録すると、App\Util\TransformerInterface タイプを実装する 2 つのサービスが作成されます。自動配線サブシステムは、どちらを使用するかを決定できません。自動配線は魔法ではないことを覚えておいてください。タイプヒントに一致する ID を持つサービスを探します。そのため、型から正しいサービス ID へのエイリアスを作成して 1 つを選択する必要があります (「サービスの依存関係を自動的に定義する (オートワイヤリング)」を参照)。場合によっては。

For instance, you may want to use the Rot13Transformer implementation by default when the TransformerInterface interface is type hinted, but use the UppercaseTransformer implementation in some specific cases. To do so, you can create a normal alias from the TransformerInterface interface to Rot13Transformer, and then create a named autowiring alias from a special string containing the interface followed by a variable name matching the one you use when doing the injection:

たとえば、TransformerInterface インターフェースがタイプ ヒンティングされている場合はデフォルトで Rot13Transformer 実装を使用したいが、特定のケースでは UppercaseTransformer 実装を使用したい場合があります。これを行うには、TransformerInterface インターフェースから Rot13Transformer への通常のエイリアスを作成し、インターフェースを含む特別な文字列から名前付きオートワイヤリング エイリアスを作成し、その後にインジェクションを行うときに使用するものと一致する変数名を続けます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Service/MastodonClient.php
namespace App\Service;

use App\Util\TransformerInterface;

class MastodonClient
{
    private $transformer;

    public function __construct(TransformerInterface $shoutyTransformer)
    {
        $this->transformer = $shoutyTransformer;
    }

    public function toot(User $user, string $key, string $status): void
    {
        $transformedStatus = $this->transformer->transform($status);

        // ... connect to Mastodon and send the transformed status
    }
}
  • 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:
    # ...

    App\Util\Rot13Transformer: ~
    App\Util\UppercaseTransformer: ~

    # the ``App\Util\UppercaseTransformer`` service will be
    # injected when an ``App\Util\TransformerInterface``
    # type-hint for a ``$shoutyTransformer`` argument is detected.
    App\Util\TransformerInterface $shoutyTransformer: '@App\Util\UppercaseTransformer'

    # If the argument used for injection does not match, but the
    # type-hint still matches, the ``App\Util\Rot13Transformer``
    # service will be injected.
    App\Util\TransformerInterface: '@App\Util\Rot13Transformer'

    App\Service\TwitterClient:
        # the Rot13Transformer will be passed as the $transformer argument
        autowire: true

        # If you wanted to choose the non-default service and do not
        # want to use a named autowiring alias, wire it manually:
        # arguments:
        #     $transformer: '@App\Util\UppercaseTransformer'
        # ...

Thanks to the App\Util\TransformerInterface alias, any argument type-hinted with this interface will be passed the App\Util\Rot13Transformer service. If the argument is named $shoutyTransformer, App\Util\UppercaseTransformer will be used instead. But, you can also manually wire any other service by specifying the argument under the arguments key.

App\Util\TransformerInterface エイリアスのおかげで、このインターフェイスで型ヒントされた引数はすべて App\Util\Rot13Transformer サービスに渡されます。また、arguments キーの下に引数を指定して、他のサービスを手動で接続します。

Fixing Non-Autowireable Arguments

Autowiring only works when your argument is an object. But if you have a scalar argument (e.g. a string), this cannot be autowired: Symfony will throw a clear exception.

自動配線は、引数がオブジェクトの場合にのみ機能します。しかし、スカラー引数 (文字列など) がある場合、これは自動配線できません: Symfony は clearException をスローします。

To fix this, you can manually wire the problematic argument in the service configuration. You wire up only the difficult arguments, Symfony takes care of the rest.

これを修正するには、サービス構成で問題のある引数を手動で配線します。あなたは難しい引数だけを接続し、残りは Symfony が処理します。

You can also use the #[Autowire] parameter attribute to instruct the autowiring logic about those arguments:

#[Autowire] パラメータ属性を使用して、これらの引数についてオートワイヤリング ロジックに指示することもできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Service/MessageGenerator.php
namespace App\Service;

use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class MessageGenerator
{
    public function __construct(
        #[Autowire(service: 'monolog.logger.request')] LoggerInterface $logger
    ) {
        // ...
    }
}

6.1

6.1

The #[Autowire] attribute was introduced in Symfony 6.1.

#[Autowire] 属性は Symfony 6.1 で導入されました。

The #[Autowire] attribute can also be used for parameters and even complex expressions:

#[Autowire] 属性は、パラメーターや複雑な式にも使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Service/MessageGenerator.php
namespace App\Service;

use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class MessageGenerator
{
    public function __construct(
        // use the %...% syntax for parameters
        #[Autowire('%kernel.project_dir%/data')]
        string $dataDir,

        #[Autowire('%kernel.debug%')]
        bool $debugMode,

        // and expressions
        #[Autowire(expression: 'service("App\\Mail\\MailerConfiguration").getMailerMethod()')]
        string $mailerMethod
    ) {
    }
    // ...
}

Autowiring other Methods (e.g. Setters and Public Typed Properties)

When autowiring is enabled for a service, you can also configure the container to call methods on your class when it's instantiated. For example, suppose you want to inject the logger service, and decide to use setter-injection:

サービスのオートワイヤリングが有効になっている場合は、コンテナがインスタンス化されたときにクラスのメソッドを呼び出すようにコンテナを構成することもできます。たとえば、ロガー サービスを注入する必要があり、setter-injection を使用することにしたとします。
  • Attributes
    属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Util/Rot13Transformer.php
namespace App\Util;

use Symfony\Contracts\Service\Attribute\Required;

class Rot13Transformer
{
    private $logger;

    #[Required]
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }

    public function transform($value): string
    {
        $this->logger->info('Transforming '.$value);
        // ...
    }
}

Autowiring will automatically call any method with the #[Required] attribute above it, autowiring each argument. If you need to manually wire some of the arguments to a method, you can always explicitly configure the method call.

オートワイヤーは、その上に #[Required] 属性を持つメソッドを自動的に呼び出し、各引数をオートワイヤーします。一部の引数をメソッドに手動で接続する必要がある場合は、いつでもメソッド呼び出しを明示的に構成できます。

If your PHP version doesn't support attributes (they were introduced in PHP 8), you can use the @required annotation instead.

PHP バージョンが属性をサポートしていない場合 (PHP 8 で導入されたもの)、代わりに @required アノテーションを使用できます。

Despite property injection having some drawbacks, autowiring with #[Required] or @required can also be applied to public typed properties:

プロパティの注入にはいくつかの欠点がありますが、#[Required] または @required を使用した自動配線は publictyped プロパティにも適用できます。
  • Attributes
    属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace App\Util;

use Symfony\Contracts\Service\Attribute\Required;

class Rot13Transformer
{
    #[Required]
    public LoggerInterface $logger;

    public function transform($value)
    {
        $this->logger->info('Transforming '.$value);
        // ...
    }
}

Autowiring Controller Action Methods

If you're using the Symfony Framework, you can also autowire arguments to your controller action methods. This is a special case for autowiring, which exists for convenience. See Controller for more details.

Symfony Framework を使用している場合は、引数を controlleraction メソッドにオートワイヤーすることもできます。これは、利便性のために存在するオートワイヤリングの特殊なケースです。詳細については、コントローラーを参照してください。

Performance Consequences

Thanks to Symfony's compiled container, there is no performance penalty for using autowiring. However, there is a small performance penalty in the dev environment, as the container may be rebuilt more often as you modify classes. If rebuilding your container is slow (possible on very large projects), you may not be able to use autowiring.

Symfony のコンパイル済みコンテナーのおかげで、オートワイヤーを使用してもパフォーマンスが低下することはありません。ただし、クラスを変更するとコンテナがより頻繁に再構築される可能性があるため、開発環境ではパフォーマンスがわずかに低下します。コンテナーの再構築が遅い場合 (非常に大規模なプロジェクトで可能)、自動配線を使用できない場合があります。

Public and Reusable Bundles

Public bundles should explicitly configure their services and not rely on autowiring. Autowiring depends on the services that are available in the container and bundles have no control over the service container of applications they are included in. You can use autowiring when building reusable bundles within your company, as you have full control over all code.

パブリック バンドルはサービスを明示的に構成する必要があり、自動配線に依存するべきではありません。すべてのコードを完全に制御できるためです。