Fabien PotencierのSymfony 2の『What is Dependency Injection?』を聞く

11376 ワード

依存注入とは何ですか?PHP実装の観点から依存注入を解析し,PHPは主にweb開発に用いられるため,Web応用例を見る.HTTPプロトコルの無状態性を克服するために、Webアプリケーションは、Webリクエスト間にユーザ情報を格納する方法を必要とする.最も簡単な方法は、クッキーを使用するか、より良いPHP内蔵のSessionメカニズムを採用することです.
$_SESSION['language']='en';

以上のコードは,セッション変数languageに言語を格納することを実現した.その後、同じユーザーの後続のリクエストでこの値を使用できます.なぜなら$SESSION配列はグローバルな変数です.呼び出し方法は次のとおりです.
$user_language = $_SESSION['language'];

依存注入はオブジェクト世界向けの概念であるため,PHP Sessionメカニズムをクラスにカプセル化し,webアプリケーションに適用する必要がある.
class SessionStorage

{

   function __construct($cookieName = 'PHP_SESS_ID')

   {

    session_name($cookieName);

    session_start();

   }

   

   function set($key, $value)

   {

    $_SESSION[$key] = $value;

   }



   function get($key)

   {

    return $_SESSION[$key];

   }



   //...

}

次に、Userクラスを定義して、より高度なインタフェースを提供します.
class User

{

    protected $storage;

    

    function __construct()

    {

    $this->$storage = new SessionStorage();

    }

    

    function setLanguage($language)

    {

    $this->storage->set('language', $language);

    }



    function getLanguage()

    {

    return $this->storage->get('language');

    }

   

    //.....

}

その後、私たちは直接使用することができます.
$user = new User();

$user->setLanguage('en');

$user_language = $user->getLanguage();

もっと柔軟にやれば?会話クッキーの名前を変えたいならどうしますか?UserクラスでSessionStorageのコンストラクション関数で指定できるハードコーディング方式がいくつかあります.
class User

{

   function __construct()

   {

      $this->storage = new SessionStorage('SESSION_ID');

   }

   //....

}

あるいはUserクラスの外で定数を定義します:STORAGE_SESSION_NAMEという大域式の定数定義は,推奨しない.
class User

{

  function __construct()

  {

    $this->storage = new SessionStorage(STORAGE_SESSION_NAME);

  }

 

  // ...

}



define('STORAGE_SESSION_NAME','SESSION_ID');

1つの方法は、セッション名をUserクラス構築関数のパラメータとして使用することです.
class User

{

  function __construct($sessionName)

  {

    $this->storage = new SessionStorage($sessionName);

  }

 

  // ...

}

 

$user = new User('SESSION_ID');

もう1つの方法は、PHPコードで一般的にセッションストレージクラスにオプション設定項目配列optionsを追加することです.
class User

{

  function __construct($storageOptions)

  {

    $this->storage = new SessionStorage($storageOptions['session_name']);

  }

 

  // ...

}

 

$user = new User(array('session_name' => 'SESSION_ID'));

実装方法はいろいろありますが、ハードコーディングでも定数に設定しても、コンストラクション関数としてのパラメータやオプション配列は最適ではありません.後者は少しよく見えますが、Userクラスのコンストラクタには自分に関係のないパラメータが積み上げられています.
続けて、もう一つの問題が来ました.もし私がSessionStorageクラスを変えたいならどうしますか?例えば、テスト時に偽のデータを作成します.あるいは、Sessionをデータベースやメモリに保存する場合は、SessionStorageクラスを変更する必要があります.現在の状況では,Userクラスを変更しなければSessionStorageクラスを変更することは不可能である.
ここでは,UserクラスでSessionStorageオブジェクトを作成するのではなく,外部作成後にUserクラスの構築方法パラメータとしてUserオブジェクトに渡す依存注入を考える.
class User

{

  function __construct($storage)

  {

    $this->storage = $storage;

  }

 

  // ...

}

OK、これが依存注入で、他にはありません!Userクラスを使用する場合は、前回よりも少し面倒な場合があります.
$storage = new SessionStorage('SESSION_ID');

$user = new User($storage);

今はUserクラスを変えない前提で、Sessionの名前を変えて、SessionStorageクラスを変えて、あなたは何をしてもいいです!
要約すると、依存注入は、コンポーネントがコンストラクタ、メソッド、またはプロパティフィールドを介して依存するオブジェクトを取得することです.
コンストラクタ注入:
class User

{

  function __construct($storage)

  {

    $this->storage = $storage;

  }

 

  // ...

}

セットアップインジェクション(メソッドインジェクション):
class User

{

  function setSessionStorage($storage)

  {

    $this->storage = $storage;

  }

 

  // ...

}

属性フィールドの入力:
class User

{

  public $sessionStorage;

}

 

$user->sessionStorage = $storage;

Symfonyでは彼らの姿が見えます
コンストラクション注入:
$dispatcher = new sfEventDispatcher();

$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));

$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));

$dispatcherオブジェクトと$storageオブジェクトを$userオブジェクトに注入します.
メソッド注入:
$transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(

  'auth'     => 'login',

  'username' => 'foo',

  'password' => 'bar',

  'ssl'      => 'ssl',

  'port'     => 465,

));

 

$mailer = new Zend_Mail();

$mailer->setDefaultTransport($transport);

この注入は、通称setter注入と呼ばれる.
Ok,これが依存注入であり,Symfony 2でサービス容器注入に発展する.柔軟な分散結合をより容易にするマルチレベル依存管理を提供します.Symfony 2の実行効率と拡張性を最も強力にサポートするService Containerです.