サービスコンテナ
現代の PHP プログラムはすべてオブジェクトです。 1 つのオブジェクトは電子メールの送信を担当し、別のオブジェクトでは情報をデータベースに保存できます。プログラムでは、製品在庫を管理するオブジェクトを作成したり、別のオブジェクトを使用してサードパーティ API からのデータを処理したりできます。結論としては、最新のプログラムは多くのことを実行でき、プログラムは独自のタスクを処理するために一緒に編成された多くのオブジェクトで構成されています。
この章では、プログラム内の多くのオブジェクトをインスタンス化、整理、取得するのに役立つ Symfony の特別な PHP オブジェクトについて説明します。 「サービス コンテナ」と呼ばれるこのオブジェクトを使用すると、プログラム内のオブジェクトの編成を標準化および一元化できます。コンテナーは物事をシンプルにし、非常に高速であり、結合を減らしながらコードの再利用性をアーキテクチャ的に向上させることに重点を置いています。すべての Symfony クラスはコンテナを使用するため、Symfony でオブジェクトを拡張、設定、使用する方法を学びます。大きな観点から見ると、サービスコンテナは Symfony の速度とスケーラビリティに最も大きく貢献しています。
最後に、サービス コンテナの構成と使用は簡単です。この章を学習すると、サービス コンテナを通じて独自のオブジェクトを簡単に作成できるようになり、サードパーティ バンドルのオブジェクトをカスタマイズすることもできます。サービス コンテナーを使用すると優れたコードを簡単に作成できるため、再利用可能でテスト可能な疎結合コードの作成を開始できます。
この章を読んだ後にさらに詳しく知りたい場合は、Dependency Injection コンポーネントを参照してください。
サービスとは ¶
簡単に言えば、サービス (Service) は、「グローバル」タスクを実行する任意のオブジェクトです。これはコンピュータ サイエンスにおける固有名詞で、「特定のタスク (電子メールの送信など) を完了するために」作成されたオブジェクトを表すために使用されます。プログラムでは、サービスが提供する特定の機能が必要なときに、いつでもサービスにアクセスできます。サービスを作成するときに特別なことをする必要はありません。タスクを実行する PHP クラスを記述するだけです。おめでとうございます。サービスが作成されました。
原則として、PHP オブジェクトをサービスにしたい場合は、プログラムのグローバル スコープで使用できる必要があります。独立した Mailer
サービスは、電子メール メッセージの送信に「グローバルに」使用されますが、送信される Message
情報オブジェクトは not サービスではありません。同様に、Product
オブジェクトはサービスではありませんが、製品をデータベースに永続化できるオブジェクトはサービスです。
これは何を示していますか? 「サービス」の観点から問題を考えることの利点は、プログラム内の各機能を一連のサービスにすでに分離しておくことです。各サービスは 1 つのことだけを実行するため、必要なときにいつでもサービスに簡単にアクセスできます。各サービスはアプリケーション内の他の機能から分離されているため、テストと構成が簡単になります。この概念は サービス指向アーキテクチャ と呼ばれ、Symfony や PHP に限定されたものではありません。一連の独立したサービス クラスを通じてプログラムを「構造化」することは、オブジェクト指向プログラミングにおける長年の実績とよく知られたベスト プラクティスです。このスキルは、どの言語でも優れた開発者になるための鍵です。
サービス コンテナとは何ですか? ¶
サービス コンテナ (サービス コンテナ/依存関係注入コンテナ) は、サービス (オブジェクト) のインスタンス化を管理する PHP オブジェクトです。 。
たとえば、電子メール メッセージを送信するための単純なクラスがあるとします。サービス コンテナーがなければ、必要に応じてオブジェクトを手動で作成する必要があります。
use Acme\HelloBundle\Mailer; $mailer = new Mailer('sendmail'); $mailer->send('ryan@example.com', ...);
簡単です。メール送信方法 (sendmail
や smtp
など) を構成できるようにする架空の Mailer
メール サービス クラス。しかし、メール サービスを別の場所で使用したい場合はどうすればよいでしょうか? Mailer
オブジェクトを毎回再構成する必要はありません。メールの送信方法を変更し、プログラム全体のすべての sendmail
を smtp
に変更する場合はどうすればよいでしょうか? Mailer
が作成されている場所をすべて見つけて、手動で更新する必要があります。
コンテナでのサービスの作成と構成 ¶
上記の質問に対する最良の答えは、サービス コンテナに Mailer オブジェクトを作成させることです。コンテナが適切に動作するには、まず Mailer サービスの作成方法をコンテナに教える必要があります。これは、YAML、XML、または PHP を使用した設定によって実現されます。
PHP:// app/config/services.phpuse Symfony\Component\DependencyInjection\Definition; $container->setDefinition('app.mailer', new Definition( 'AppBundle\Mailer', array('sendmail')));
XML:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="app.mailer" class="AppBundle\Mailer"> <argument>sendmail</argument> </service> </services></container>
YAML:# app/config/services.ymlservices: app.mailer: class: AppBundle\Mailer arguments: [sendmail]
Symfony が初期化されると、設定情報コンテナ (デフォルト設定) に基づいてサービスが確立されます。ファイルは app/config/config.yml
です)。ロードされる正しい構成ファイルは、「特定の環境」構成ファイルをロードする AppKernel::registerContainerConfiguration()
メソッドによって示されます (config_dev.yml などは開発開発環境用であり、 config_prod.yml
は実稼働環境用です)。
Acme\HelloBundle\Mailer オブジェクトのインスタンスは、サービス コンテナを通じてすでに利用可能です。コンテナーは、get() ショートカット メソッドを通じて標準の Symfony コントローラーから直接取得できます。
class HelloController extends Controller{ // ... public function sendEmailAction() { // ... $mailer = $this->get('app.mailer'); $mailer->send('ryan@foobar.net', ...); }}コンテナから
app.mailer サービスをリクエストすると、コンテナはオブジェクトを構築し、それを返します (インスタンス化後)。これは、サービス コンテナーを使用することのもう 1 つの利点です。つまり、必要な場合を除き、サービスは構築されません。サービスを定義しても、リクエスト中にそのサービスが使用されなかった場合、そのサービスは作成されません。これによりメモリが節約され、プログラムの実行が高速になります。これは、多数のサービスを定義してもパフォーマンスが低下することはほとんどないことも意味します。決して使用されないサービスは決して構築されません。
非共有サービスを定義する方法の記事を参照してください。
app.mailer サービス。
¶
コンテナを使用して新しいサービスを作成するプロセスは、非常にシンプルで簡単です。パラメーターを使用すると、サービスの定義をより柔軟かつ整然としたものにすることができます。PHP:// app/config/services.phpuse Symfony\Component\DependencyInjection\Definition; $container->setParameter('app.mailer.transport', 'sendmail'); $container->setDefinition('app.mailer', new Definition( 'AppBundle\Mailer', array('%app.mailer.transport%')));
XML:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <parameters> <parameter key="app.mailer.transport">sendmail</parameter> </parameters> <services> <service id="app.mailer" class="AppBundle\Mailer"> <argument>%app.mailer.transport%</argument> </service> </services></container>
YAML:# app/config/services.ymlparameters: app.mailer.transport: sendmailservices: app.mailer: class: AppBundle\Mailer arguments: ['%app.mailer.transport%']
app.mailer.transport を
% パーセント記号で囲むことにより、コンテナはその名前に対応するパラメータを探すことができます。コンテナ自体が生成されると、各パラメータの値がサービス定義に復元されます。
@ で始まる文字列を YAML ファイルのパラメーター値 (非常に安全な電子メール パスワードなど) として使用する場合は、次のことを行う必要があります。エスケープ用の別の
# 記号を追加します (この状況は YAML 形式の構成ファイルにのみ適用されます)
# app/config/parameters.ymlparameters: # This will be parsed as string '@securepass' mailer_password: '@@securepass'
## |