22
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Symfony2のサービスコンテナについて

Last updated at Posted at 2015-08-28

公式の解説
日本語版

日本語版記事には,

Service Container (サービスコンテナ) (または 依存性注入コンテナ) はサービスのインスタンス化を管理する単純な PHP オブジェクトです。

と書かれています(最初は???でした).

要するに,サービス(PHPのクラスに対応するもの)をSymfony側に登録することにより,後で再利用できるようにするためのものらしいです.

では,単純にクラスをnewでインスタンス化して使うのと何が違うのかというと,「依存性注入」によって,引数やその他の情報を設定ファイル上から定義できる点です.
依存性注入については,以下の記事がうまくまとまっていると思います.
猿でも分かる! Dependency Injection: 依存性の注入

ここで,依存性として注入できるのは,通常の引数だけでなく,設定ファイルのパラメータの値やリクエストオブジェクトやセッションオブジェクト,さらにサービスコンテナ自体など,多岐に渡ります.

簡単な例を挙げると,

src/ExampleBundle/Resources/config/services.yml
# サービスを設定ファイルに登録する
# このyamlファイルは,最終的にapp/config/config.ymlにロードされる必要がある
services:
    example.service1:
        class: ExampleBundle\Services\Service1
        arguments: [ ]
    example.logic1:
        class: ExampleBundle\Logic\Logic1
        arguments: [ @service_container ] # 引数としてサービスコンテナを注入
src/ExampleBundle/Logic/Logic1.php
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();
    }
    
}
src/ExampleBundle/Services/service1.php
namespace ExampleBundle\Services;

class Service1 {

    public function func() {
        # 処理
    }
    
}

このように,サービスコンテナを使うことで,newを使わず,サービスとしてクラスをインスタンス化することができます.

もう少し例を複雑にすると,

src/ExampleBundle/Resources/config/services.yml
# 設定ファイルに記述するパラメータ
parameters:
    example.message: hoge
    
# サービスを設定ファイルに登録する
services:
    example.service2:
        class: ExampleBundle\Services\Service2
        arguments: [ @service_container, 'fuga' ] # 引数としてサービスコンテナと文字列を注入
    example.logic2:
        class: ExampleBundle\Logic\Logic2
        arguments: [ @service_container ] # 引数としてサービスコンテナを注入
src/ExampleBundle/Logic/Logic2.php
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
    }
    
}
src/ExampleBundle/Services/service2.php
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クラスを継承したクラス)では,特に設定することなくサービスコンテナを使うことができます.

src/ExampleBundle/ExampleController.php
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>');
    }
    
}
22
29
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?