Compiling the Container

The service container can be compiled for various reasons. These reasons include checking for any potential issues such as circular references and making the container more efficient by resolving parameters and removing unused services. Also, certain features - like using parent services - require the container to be compiled.

サービス コンテナは、さまざまな理由でコンパイルできます。これらの理由には、循環参照などの潜在的な問題のチェック、およびパラメーターの解決と未使用のサービスの削除によるコンテナーの効率化が含まれます。また、特定の機能 (親サービスの使用など) では、コンテナーをコンパイルする必要があります。

It is compiled by running:

以下を実行してコンパイルします。
1
$container->compile();

The compile method uses Compiler Passes for the compilation. The DependencyInjection component comes with several passes which are automatically registered for compilation. For example the CheckDefinitionValidityPass checks for various potential issues with the definitions that have been set in the container. After this and several other passes that check the container's validity, further compiler passes are used to optimize the configuration before it is cached. For example, private services and abstract services are removed and aliases are resolved.

compile メソッドは、コンパイルに Compiler Passes を使用します。 DependencyInjection コンポーネントには、コンパイル用に自動的に登録されるいくつかのパスが付属しています。たとえば、CheckDefinitionValidityPass は、コンテナーに設定されている定義に関するさまざまな潜在的な問題をチェックします。このパスとコンテナの有効性をチェックする他のいくつかのパスの後、追加のコンパイラ パスを使用して、構成がキャッシュされる前に最適化されます。たとえば、プライベート サービスと抽象サービスは削除され、エイリアスは解決されます。

Managing Configuration with Extensions

As well as loading configuration directly into the container as shown in The DependencyInjection Component, you can manage it by registering extensions with the container. The first step in the compilation process is to load configuration from any extension classes registered with the container. Unlike the configuration loaded directly, they are only processed when the container is compiled. If your application is modular then extensions allow each module to register and manage their own service configuration.

DependencyInjection コンポーネントに示されているように、構成をコンテナーに直接ロードするだけでなく、コンテナーに拡張機能を登録することで構成を管理できます。コンパイル プロセスの最初のステップは、コンテナーに登録されている拡張クラスから構成を読み込むことです。直接ロードされた構成とは異なり、コンテナーがコンパイルされたときにのみ処理されます。アプリケーションがモジュール式の場合、拡張機能により、各モジュールが独自のサービス構成を登録および管理できるようになります。

The extensions must implement ExtensionInterface and can be registered with the container with:

拡張機能は、ExtensionInterface を実装する必要があり、以下を使用してコンテナーに登録できます。
1
$container->registerExtension($extension);

The main work of the extension is done in the load() method. In the load() method you can load configuration from one or more configuration files as well as manipulate the container definitions using the methods shown in How to work with Service Definition Objects.

拡張機能の主な作業は、load() メソッドで行われます。 load() メソッドでは、1 つ以上の構成ファイルから構成をロードしたり、サービス定義オブジェクトの操作方法に示されているメソッドを使用してコンテナー定義を操作したりできます。

The load() method is passed a fresh container to set up, which is then merged afterwards into the container it is registered with. This allows you to have several extensions managing container definitions independently. The extensions do not add to the containers configuration when they are added but are processed when the container's compile() method is called.

load() メソッドには、設定する新しいコンテナが渡され、その後、登録されているコンテナにマージされます。これにより、コンテナ定義を個別に管理する複数の拡張機能を持つことができます。拡張機能は、追加時にコンテナ構成に追加されませんが、コンテナの compile() メソッドが呼び出されたときに処理されます。

A very simple extension may just load configuration files into the container:

非常に単純な拡張機能は、構成ファイルをコンテナーにロードするだけです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;

class AcmeDemoExtension implements ExtensionInterface
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');
    }

    // ...
}

This does not gain very much compared to loading the file directly into the overall container being built. It just allows the files to be split up among the modules/bundles. Being able to affect the configuration of a module from configuration files outside of the module/bundle is needed to make a complex application configurable. This can be done by specifying sections of config files loaded directly into the container as being for a particular extension. These sections on the config will not be processed directly by the container but by the relevant Extension.

これは、構築中のコンテナ全体にファイルを直接ロードする場合と比べて、あまりメリットがありません。モジュール/バンドル間でファイルを分割できるようにするだけです。複雑なアプリケーションを構成可能にするには、モジュール/バンドルの外部の構成ファイルからモジュールの構成に影響を与えることができる必要があります。これは、コンテナに直接読み込まれる構成ファイルのセクションを特定の拡張子として指定することで実行できます。構成のこれらのセクションは、コンテナーによって直接処理されるのではなく、関連する拡張機能によって処理されます。

The Extension must specify a getAlias() method to implement the interface:

拡張機能は、インターフェイスを実装するために getAlias() メソッドを指定する必要があります。
1
2
3
4
5
6
7
8
9
10
11
// ...

class AcmeDemoExtension implements ExtensionInterface
{
    // ...

    public function getAlias()
    {
        return 'acme_demo';
    }
}

For YAML configuration files specifying the alias for the extension as a key will mean that those values are passed to the Extension's load() method:

拡張機能のエイリアスを akey として指定する YAML 構成ファイルの場合、これらの値が拡張機能の load() メソッドに渡されることを意味します。
1
2
3
4
# ...
acme_demo:
    foo: fooValue
    bar: barValue

If this file is loaded into the configuration then the values in it are only processed when the container is compiled at which point the Extensions are loaded:

このファイルが構成に読み込まれると、その中の値は、拡張機能が読み込まれる時点でコンテナがコンパイルされるときにのみ処理されます。
1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

$containerBuilder = new ContainerBuilder();
$containerBuilder->registerExtension(new AcmeDemoExtension);

$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__));
$loader->load('config.yaml');

// ...
$containerBuilder->compile();

Note

ノート

When loading a config file that uses an extension alias as a key, the extension must already have been registered with the container builder or an exception will be thrown.

拡張機能のエイリアスをキーとして使用する構成ファイルをロードする場合、拡張機能は既にコンテナー ビルダーに登録されている必要があります。登録されていない場合、例外がスローされます。

The values from those sections of the config files are passed into the first argument of the load() method of the extension:

構成ファイルのこれらのセクションの値は、拡張機能の load() メソッドの最初の引数に渡されます。
1
2
3
4
5
public function load(array $configs, ContainerBuilder $container)
{
    $foo = $configs[0]['foo']; //fooValue
    $bar = $configs[0]['bar']; //barValue
}

The $configs argument is an array containing each different config file that was loaded into the container. You are only loading a single config file in the above example but it will still be within an array. The array will look like this:

$configs 引数は、コンテナーにロードされたそれぞれの構成ファイルを含む配列です。上記の例では単一の構成ファイルのみをロードしていますが、それでも配列内にあります。配列は次のようになります。
1
2
3
4
5
6
[
    [
        'foo' => 'fooValue',
        'bar' => 'barValue',
    ],
]

Whilst you can manually manage merging the different files, it is much better to use the Config component to merge and validate the config values. Using the configuration processing you could access the config value this way:

異なるファイルのマージを手動で管理することもできますが、Config コンポーネントを使用してマージし、構成値を検証する方がはるかに優れています。構成処理を使用すると、次の方法で構成値にアクセスできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Config\Definition\Processor;
// ...

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $processor = new Processor();
    $config = $processor->processConfiguration($configuration, $configs);

    $foo = $config['foo']; //fooValue
    $bar = $config['bar']; //barValue

    // ...
}

There are a further two methods you must implement. One to return the XML namespace so that the relevant parts of an XML config file are passed to the extension. The other to specify the base path to XSD files to validate the XML configuration:

さらに 2 つの方法を実装する必要があります。 XML 構成ファイルの関連部分が拡張機能に渡されるように、XML 名前空間を返すもの。もう 1 つは、XSD ファイルへのベース パスを指定して、XML 構成を検証します。
1
2
3
4
5
6
7
8
9
public function getXsdValidationBasePath()
{
    return __DIR__.'/../Resources/config/';
}

public function getNamespace()
{
    return 'http://www.example.com/symfony/schema/';
}

Note

ノート

XSD validation is optional, returning false from the getXsdValidationBasePath() method will disable it.

XSD 検証はオプションです。getXsdValidationBasePath() メソッドから false を返すと無効になります。

The XML version of the config would then look like this:

構成の XML バージョンは次のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:acme-demo="http://www.example.com/schema/dic/acme_demo"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd
        http://www.example.com/schema/dic/acme_demo
        https://www.example.com/schema/dic/acme_demo/acme_demo-1.0.xsd"
>
    <acme-demo:config>
        <acme_demo:foo>fooValue</acme_demo:foo>
        <acme_demo:bar>barValue</acme_demo:bar>
    </acme-demo:config>
</container>

Note

ノート

In the Symfony full-stack Framework there is a base Extension class which implements these methods as well as a shortcut method for processing the configuration. See How to Load Service Configuration inside a Bundle for more details.

Symfony フルスタック フレームワークには、これらのメソッドを実装するベースの Extension クラスと、構成を処理するためのショートカット メソッドがあります。詳細については、バンドル内にサービス構成をロードする方法を参照してください。

The processed config value can now be added as container parameters as if it were listed in a parameters section of the config file but with the additional benefit of merging multiple files and validation of the configuration:

処理された構成値は、構成ファイルのパラメーター セクションにリストされているかのようにコンテナー パラメーターとして追加できるようになりましたが、複数のファイルをマージして構成を検証するという追加の利点があります。
1
2
3
4
5
6
7
8
9
10
public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $processor = new Processor();
    $config = $processor->processConfiguration($configuration, $configs);

    $container->setParameter('acme_demo.FOO', $config['foo']);

    // ...
}

More complex configuration requirements can be catered for in the Extension classes. For example, you may choose to load a main service configuration file but also load a secondary one only if a certain parameter is set:

Extensionclasses では、より複雑な構成要件に対応できます。たとえば、特定のパラメーターが設定されている場合にのみ、メインのサービス構成ファイルをロードするだけでなく、2 番目の構成ファイルもロードすることを選択できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $processor = new Processor();
    $config = $processor->processConfiguration($configuration, $configs);

    $loader = new XmlFileLoader(
        $container,
        new FileLocator(__DIR__.'/../Resources/config')
    );
    $loader->load('services.xml');

    if ($config['advanced']) {
        $loader->load('advanced.xml');
    }
}

Note

ノート

Just registering an extension with the container is not enough to get it included in the processed extensions when the container is compiled. Loading config which uses the extension's alias as a key as in the above examples will ensure it is loaded. The container builder can also be told to load it with its loadFromExtension() method:

拡張機能をコンテナーに登録するだけでは、コンテナーのコンパイル時に処理済みの拡張機能に含めるには十分ではありません。上記の例のように、拡張機能のエイリアスをキーとして使用する構成を読み込むと、確実に読み込まれます。コンテナ ビルダーは、loadFromExtension() メソッドを使用してロードするように指示することもできます。
1
2
3
4
5
6
7
use Symfony\Component\DependencyInjection\ContainerBuilder;

$containerBuilder = new ContainerBuilder();
$extension = new AcmeDemoExtension();
$containerBuilder->registerExtension($extension);
$containerBuilder->loadFromExtension($extension->getAlias());
$containerBuilder->compile();

Note

ノート

If you need to manipulate the configuration loaded by an extension then you cannot do it from another extension as it uses a fresh container. You should instead use a compiler pass which works with the full container after the extensions have been processed.

拡張機能によってロードされた構成を操作する必要がある場合、新しいコンテナーを使用するため、別の拡張機能から操作することはできません。代わりに、拡張機能が処理された後に完全なコンテナーで動作するコンパイラ パスを使用する必要があります。

Prepending Configuration Passed to the Extension

An Extension can prepend the configuration of any Bundle before the load() method is called by implementing PrependExtensionInterface:

拡張機能は、PrependExtensionInterface を実装することによって load() メソッドが呼び出される前に、任意のバンドルの構成を前に追加できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
// ...

class AcmeDemoExtension implements ExtensionInterface, PrependExtensionInterface
{
    // ...

    public function prepend(ContainerBuilder $container)
    {
        // ...

        $container->prependExtensionConfig($name, $config);

        // ...
    }
}

For more details, see How to Simplify Configuration of Multiple Bundles, which is specific to the Symfony Framework, but contains more details about this feature.

詳細については、複数のバンドルの構成を簡素化する方法を参照してください。これは Symfony フレームワークに固有のものですが、この機能の詳細が含まれています。

Execute Code During Compilation

You can also execute custom code during compilation by writing your own compiler pass. By implementing CompilerPassInterface in your extension, the added process() method will be called during compilation:

また、独自のコンパイラ パスを記述して、コンパイル中にカスタム コードを実行することもできます。拡張機能に CompilerPassInterface を実装すると、追加された process() メソッドがコンパイル中に呼び出されます。
1
2
3
4
5
6
7
8
9
10
11
12
// ...
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

class AcmeDemoExtension implements ExtensionInterface, CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        // ... do something during the compilation
    }

    // ...
}

As process() is called after all extensions are loaded, it allows you to edit service definitions of other extensions as well as retrieving information about service definitions.

すべての拡張機能がロードされた後に process() が呼び出されるため、他の拡張機能のサービス定義を編集したり、サービス定義に関する情報を取得したりできます。

The container's parameters and definitions can be manipulated using the methods described in How to work with Service Definition Objects.

コンテナーのパラメーターと定義は、サービス定義オブジェクトの操作方法で説明されている方法を使用して操作できます。

Note

ノート

Please note that the process() method in the extension class is called during the PassConfig::TYPE_BEFORE_OPTIMIZATION step. You can read the next section if you need to edit the container during another step.

拡張クラスの process() メソッドは PassConfig::TYPE_BEFORE_OPTIMIZATION ステップで呼び出されることに注意してください。別のステップでコンテナーを編集する必要がある場合は、次のセクションをお読みください。

Note

ノート

As a rule, only work with services definition in a compiler pass and do not create service instances. In practice, this means using the methods has(), findDefinition(), getDefinition(), setDefinition(), etc. instead of get(), set(), etc.

原則として、コンパイラ パスでサービス定義のみを使用し、サービス インスタンスを作成しないでください。実際には、shas()、findDefinition()、getDefinition()、setDefinition() などのメソッドを使用することを意味します。 get()、set() などの代わりに

Tip

ヒント

Make sure your compiler pass does not require services to exist. Abort the method call if some required service is not available.

コンパイラ パスがサービスの存在を必要としないことを確認してください。必要なサービスが利用できない場合は、メソッド呼び出しを中止します。

A common use-case of compiler passes is to search for all service definitions that have a certain tag, in order to dynamically plug each one into other services. See the section on service tags for an example.

コンパイラ パスの一般的な使用例は、特定のタグを持つすべてのサービス定義を検索して、それぞれを他のサービスに動的にプラグインすることです。例については、サービス タグのセクションを参照してください。

Creating Separate Compiler Passes

Sometimes, you need to do more than one thing during compilation, want to use compiler passes without an extension or you need to execute some code at another step in the compilation process. In these cases, you can create a new class implementing the CompilerPassInterface:

コンパイル中に複数のことを行う必要がある場合や、拡張子なしでコンパイラ パスを使用したい場合や、コンパイル プロセスの別のステップでコードを実行する必要がある場合があります。このような場合、CompilerPassInterface を実装する新しいクラスを作成できます。
1
2
3
4
5
6
7
8
9
10
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class CustomPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        // ... do something during the compilation
    }
}

You then need to register your custom pass with the container:

次に、カスタム パスをコンテナーに登録する必要があります。
1
2
3
4
use Symfony\Component\DependencyInjection\ContainerBuilder;

$containerBuilder = new ContainerBuilder();
$containerBuilder->addCompilerPass(new CustomPass());

Note

ノート

Compiler passes are registered differently if you are using the full-stack framework, see How to Work with Compiler Passes for more details.

full-stackframework を使用している場合、コンパイラ パスは異なる方法で登録されます。詳細については、コンパイラ パスの使用方法を参照してください。

Controlling the Pass Ordering

The default compiler passes are grouped into optimization passes and removal passes. The optimization passes run first and include tasks such as resolving references within the definitions. The removal passes perform tasks such as removing private aliases and unused services. When registering compiler passes using addCompilerPass(), you can configure when your compiler pass is run. By default, they are run before the optimization passes.

デフォルトのコンパイラ パスは、最適化パスと削除パスにグループ化されます。最適化パスが最初に実行され、定義内の参照の解決などのタスクが含まれます。削除パスは、プライベート エイリアスや未使用のサービスの削除などのタスクを実行します。 addCompilerPass() を使用してコンパイラパスを登録すると、コンパイラパスがいつ実行されるかを構成できます。デフォルトでは、最適化がパスする前に実行されます。

You can use the following constants to determine when your pass is executed:

次の定数を使用して、パスがいつ実行されるかを判断できます。
  • PassConfig::TYPE_BEFORE_OPTIMIZATION
    PassConfig::TYPE_BEFORE_OPTIMIZATION
  • PassConfig::TYPE_OPTIMIZE
    PassConfig::TYPE_OPTIMIZE
  • PassConfig::TYPE_BEFORE_REMOVING
    PassConfig::TYPE_BEFORE_REMOVING
  • PassConfig::TYPE_REMOVE
    PassConfig::TYPE_REMOVE
  • PassConfig::TYPE_AFTER_REMOVING
    PassConfig::TYPE_AFTER_REMOVING

For example, to run your custom pass after the default removal passes have been run, use:

たとえば、デフォルトの削除パスが実行された後にカスタム パスを実行するには、次を使用します。
1
2
3
4
5
// ...
$containerBuilder->addCompilerPass(
    new CustomPass(),
    PassConfig::TYPE_AFTER_REMOVING
);

You can also control the order in which compiler passes are run for each compilation phase. Use the optional third argument of addCompilerPass() to set the priority as an integer number. The default priority is 0 and the higher its value, the earlier it's executed:

各コンパイル フェーズでコンパイラ パスが実行される順序を制御することもできます。 addCompilerPass() のオプションの 3 番目の引数を使用して、優先度を整数として設定します。デフォルトの優先度は 0 で、その値が高いほど早く実行されます。
1
2
3
4
5
6
7
8
// ...
// FirstPass is executed after SecondPass because its priority is lower
$container->addCompilerPass(
    new FirstPass(), PassConfig::TYPE_AFTER_REMOVING, 10
);
$container->addCompilerPass(
    new SecondPass(), PassConfig::TYPE_AFTER_REMOVING, 30
);

Dumping the Configuration for Performance

Using configuration files to manage the service container can be much easier to understand than using PHP once there are a lot of services. This ease comes at a price though when it comes to performance as the config files need to be parsed and the PHP configuration built from them. The compilation process makes the container more efficient but it takes time to run. You can have the best of both worlds though by using configuration files and then dumping and caching the resulting configuration. The PhpDumper serves at dumping the compiled container:

構成ファイルを使用してサービス コンテナーを管理すると、PHP を使用するよりもはるかに理解しやすくなります。ただし、設定ファイルを解析し、それらから PHP 設定を構築する必要があるため、パフォーマンスに関しては、この容易さには代償が伴います。コンパイル プロセスにより、コンテナーはより効率的になりますが、実行には時間がかかります。ただし、構成ファイルを使用し、結果の構成をダンプしてキャッシュすることで、両方の長所を活かすことができます。 PhpDumper は、コンパイルされたコンテナーをダンプするときに機能します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;

$file = __DIR__ .'/cache/container.php';

if (file_exists($file)) {
    require_once $file;
    $container = new ProjectServiceContainer();
} else {
    $containerBuilder = new ContainerBuilder();
    // ...
    $containerBuilder->compile();

    $dumper = new PhpDumper($containerBuilder);
    file_put_contents($file, $dumper->dump());
}

Tip

ヒント

The file_put_contents() function is not atomic. That could cause issues in a production environment with multiple concurrent requests. Instead, use the dumpFile() method from Symfony Filesystem component or other methods provided by Symfony (e.g. $containerConfigCache->write()) which are atomic.

file_put_contents() 関数はアトミックではありません。これにより、複数の同時リクエストがある本番環境で問題が発生する可能性があります。代わりに、Symfony Filesystem コンポーネントの dumpFile() メソッド、または Symfony が提供するその他のアトミックなメソッド (例: $containerConfigCache->write()) を使用してください。

ProjectServiceContainer is the default name given to the dumped container class. However, you can change this with the class option when you dump it:

ProjectServiceContainer は、ダンプされたコンテナ クラスに付けられるデフォルト名です。ただし、ダンプするときにクラスオプションでこれを変更できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...
$file = __DIR__ .'/cache/container.php';

if (file_exists($file)) {
    require_once $file;
    $container = new MyCachedContainer();
} else {
    $containerBuilder = new ContainerBuilder();
    // ...
    $containerBuilder->compile();

    $dumper = new PhpDumper($containerBuilder);
    file_put_contents(
        $file,
        $dumper->dump(['class' => 'MyCachedContainer'])
    );
}

You will now get the speed of the PHP configured container with the ease of using configuration files. Additionally dumping the container in this way further optimizes how the services are created by the container.

これで、構成ファイルを簡単に使用して、PHP 構成済みコンテナーの速度を得ることができます。さらに、この方法でコンテナーをダンプすると、コンテナーによってサービスが作成される方法がさらに最適化されます。

In the above example you will need to delete the cached container file whenever you make any changes. Adding a check for a variable that determines if you are in debug mode allows you to keep the speed of the cached container in production but getting an up to date configuration whilst developing your application:

上記の例では、変更を加えるたびに、キャッシュされたコンテナー ファイルを削除する必要があります。デバッグ モードにあるかどうかを決定する変数のチェックを追加すると、キャッシュされたコンテナーの速度を本番環境で維持しながら、アプリケーションの開発中に最新の構成を取得できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ...

// based on something in your project
$isDebug = ...;

$file = __DIR__ .'/cache/container.php';

if (!$isDebug && file_exists($file)) {
    require_once $file;
    $container = new MyCachedContainer();
} else {
    $containerBuilder = new ContainerBuilder();
    // ...
    $containerBuilder->compile();

    if (!$isDebug) {
        $dumper = new PhpDumper($containerBuilder);
        file_put_contents(
            $file,
            $dumper->dump(['class' => 'MyCachedContainer'])
        );
    }
}

This could be further improved by only recompiling the container in debug mode when changes have been made to its configuration rather than on every request. This can be done by caching the resource files used to configure the container in the way described in "Caching based on Resources" in the config component documentation.

これは、リクエストごとではなく、構成に変更が加えられたときにのみデバッグモードでコンテナーを再コンパイルすることで、さらに改善される可能性があります。これは、構成コンポーネントのドキュメントの「リソースに基づくキャッシュ」で説明されている方法で、コンテナーの構成に使用されるリソース ファイルをキャッシュすることで実行できます。

You do not need to work out which files to cache as the container builder keeps track of all the resources used to configure it, not just the configuration files but the extension classes and compiler passes as well. This means that any changes to any of these files will invalidate the cache and trigger the container being rebuilt. You need to ask the container for these resources and use them as metadata for the cache:

コンテナビルダーは、構成ファイルだけでなく、拡張クラスとコンパイラパスも同様に、構成に使用されるすべてのリソースを追跡するため、どのファイルをキャッシュするかを考える必要はありません。キャッシュを無効にし、コンテナーの再構築をトリガーします。コンテナーにこれらのリソースを要求し、それらをキャッシュのメタデータとして使用する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ...

// based on something in your project
$isDebug = ...;

$file = __DIR__ .'/cache/container.php';
$containerConfigCache = new ConfigCache($file, $isDebug);

if (!$containerConfigCache->isFresh()) {
    $containerBuilder = new ContainerBuilder();
    // ...
    $containerBuilder->compile();

    $dumper = new PhpDumper($containerBuilder);
    $containerConfigCache->write(
        $dumper->dump(['class' => 'MyCachedContainer']),
        $containerBuilder->getResources()
    );
}

require_once $file;
$container = new MyCachedContainer();

Now the cached dumped container is used regardless of whether debug mode is on or not. The difference is that the ConfigCache is set to debug mode with its second constructor argument. When the cache is not in debug mode the cached container will always be used if it exists. In debug mode, an additional metadata file is written with all the involved resource files. These are then checked to see if their timestamps have changed, if they have the cache will be considered stale.

現在、デバッグ モードがオンかどうかに関係なく、キャッシュされたダンプ コンテナが使用されます。違いは、ConfigCache が 2 番目のコンストラクター引数で debugmode に設定されていることです。キャッシュがデバッグモードでない場合、キャッシュされたコンテナーが存在する場合は常にそれが使用されます。デバッグ モードでは、関連するすべてのリソース ファイルを含む追加のメタデータ ファイルが書き込まれます。次に、これらのタイムスタンプが変更されているかどうかがチェックされます。変更されている場合、キャッシュは古いと見なされます。

Note

ノート

In the full-stack framework the compilation and caching of the container is taken care of for you.

フルスタック フレームワークでは、コンテナーのコンパイルとキャッシュが自動的に処理されます。