日本語版記事には,
Service Container (サービスコンテナ) (または 依存性注入コンテナ) はサービスのインスタンス化を管理する単純な PHP オブジェクトです。
と書かれています(最初は???でした).
要するに,サービス(PHPのクラスに対応するもの)をSymfony側に登録することにより,後で再利用できるようにするためのものらしいです.
では,単純にクラスをnewでインスタンス化して使うのと何が違うのかというと,「依存性注入」によって,引数やその他の情報を設定ファイル上から定義できる点です.
依存性注入については,以下の記事がうまくまとまっていると思います.
猿でも分かる! Dependency Injection: 依存性の注入
ここで,依存性として注入できるのは,通常の引数だけでなく,設定ファイルのパラメータの値やリクエストオブジェクトやセッションオブジェクト,さらにサービスコンテナ自体など,多岐に渡ります.
簡単な例を挙げると,
# サービスを設定ファイルに登録する
# このyamlファイルは,最終的にapp/config/config.ymlにロードされる必要がある
services:
example.service1:
class: ExampleBundle\Services\Service1
arguments: [ ]
example.logic1:
class: ExampleBundle\Logic\Logic1
arguments: [ @service_container ] # 引数としてサービスコンテナを注入
namespace ExampleBundle\Logic;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class Logic1 {
public function __construct(Container $container) { # コンストラクタの引数にサービスコンテナが注入される
$this->container = $container;
}
public function exec() {
$service1 = $this->container->get('example.service1'); # サービスの呼び出し
return $service1->func();
}
}
namespace ExampleBundle\Services;
class Service1 {
public function func() {
# 処理
}
}
このように,サービスコンテナを使うことで,newを使わず,サービスとしてクラスをインスタンス化することができます.
もう少し例を複雑にすると,
# 設定ファイルに記述するパラメータ
parameters:
example.message: hoge
# サービスを設定ファイルに登録する
services:
example.service2:
class: ExampleBundle\Services\Service2
arguments: [ @service_container, 'fuga' ] # 引数としてサービスコンテナと文字列を注入
example.logic2:
class: ExampleBundle\Logic\Logic2
arguments: [ @service_container ] # 引数としてサービスコンテナを注入
namespace ExampleBundle\Logic;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class Logic2 {
public function __construct(Container $container) { # コンストラクタの引数にサービスコンテナが注入される
$this->container = $container;
}
public function exec() {
$service1 = $this->container->get('example.service2'); # サービスの呼び出し
$request = $this->container->get('request'); # 現在のリクエストオブジェクトを取得
$currentUrl = $request->getUri(); # 現在のリクエストのURLを取得
$session = $request->getSession(); # 現在のセッションオブジェクトを取得
# ...
return $service1->func(); # hogefuga
}
}
namespace ExampleBundle\Services;
class Service2 {
public function __construct(Container $container, $str) { # コンストラクタの引数にサービスコンテナと文字列が注入される
$this->container = $container;
$this->str = $str;
}
public function func() {
$message = $this->container->getParameter('example.message'); # パラメータの取得
return $message . $this->$str;
}
}
こんな感じで,設定ファイルに記述したパラメータを取得したり,現在のリクエストオブジェクトを取得したりすることができます.
コントローラ以外のクラス内でパラメータやリクエストオブジェクトを取得するためには,実質的にこの方法を使わざるを得ないため(パラメータについては,直接YAMLを読み込むこともできなくはないですが),基本的に自作したクラスはサービスとして登録するようにしておくと良いと思います.
もっと早くこの方法を知りたかったです…
ちなみに,コントローラ(Controllerクラスを継承したクラス)では,特に設定することなくサービスコンテナを使うことができます.
namespace ExampleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class ExampleController extends Controller {
# コンストラクタの定義は不要
public function indexAction($name) {
# ロガーサービスを取得
# コントローラクラスでは,"$this->get('hoge')"が"$this->container->get('hoge')"のショートカットとして使うことができ,
# この行は,"$logger = $this->container->get('logger');"と等価になっている
$logger = $this->get('logger');
$logger->info('hoge'); # ログが出力される
return new Response('<html><body>fuga</body></html>');
}
}