この記事は、PHP 依存関係注入コンテナーの実装に関するシリーズの最初の章です。
今日は、コンテナー (コンテナー) については話さないようにしましょう。まず、いくつかの具体的な例を使用して、依存関係注入の概念を紹介し、この依存関係注入モデルがどのような問題を解決できるのか、また開発者にどのようなメリットをもたらすのかを説明します。
依存関係注入の概念をすでに知っている場合は、この記事をスキップしてください。
依存性注入は、私が知っている最も単純な設計パターンの 1 つかもしれません。多くの場合、依存性注入を無意識に使用したことがあるかもしれません。しかし、それは説明するのが最も難しいものの一つでもあります。その理由の 1 つは、依存関係注入を導入する例のほとんどが実用的な意味を欠いており、理解しにくいことにあると思います。 PHP は主に Web 開発に使用されるため、まず簡単な Web 開発の例を見てみましょう。
HTTP 自体はステートレスな接続プロトコルであり、顧客が WEB リクエストを開始したときにアプリケーションがユーザー情報を保存できるようにするには、ストレージ状態の対話を実現するテクノロジーを使用する必要があります。もちろん、最も簡単な方法は Cookie を使用することですが、より良い方法は PHP の組み込みセッション メカニズムです。
$_SESSION['language'] = 'fr';
上記のコードは、ユーザー言語を language という名前のセッション変数に保存するため、ユーザーによる後続のリクエストでは、グローバル配列 $_SESSION を通じて言語を取得できます:
$user_language = $_SESSION['language'];
依存性注入は主にオブジェクト指向開発に使用されますここで、PHP セッション メカニズムをカプセル化する SessionStorage クラスがあると仮定します:
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 クラスを使用するには:
$user = new User(); $user->setLanguage('fr'); $user_language = $user->getLanguage();
プログラムでより優れたスケーラビリティが必要でない限り、すべてが素晴らしいです。ここで、session_id を保存する COOKIE キーの値を変更するとします。次に、いくつかの代替方法を示します。
User クラスで SessionStorage インスタンスを作成するときは、SessionStorage コンストラクターにハードコーディングされた文字列 'SESSION_ID' を使用します。 User クラスの外部に定数 (STORAGE_SESSION_NAME という名前) を設定します
class User { function __construct() { $this->storage = new SessionStorage('SESSION_ID'); } // ... }User クラスのコンストラクターのパラメーターを通じてセッション名を渡します
class User { function __construct() { $this->storage = new SessionStorage(STORAGE_SESSION_NAME); } // ... } define('STORAGE_SESSION_NAME', 'SESSION_ID');引き続き User クラスのコンストラクターのパラメーターを通じてセッション名を渡しますが、今回はパラメータが使用されます 配列アプローチ
class User { function __construct($sessionName) { $this->storage = new SessionStorage($sessionName); } // ... } $user = new User('SESSION_ID');上記のアプローチはすべて悪いです。 ユーザー クラスでセッション名をハードコーディングしても、実際には問題は解決されません。将来、session_id を保存する COOKIE キーの値を変更する必要がある場合は、ユーザー クラス (User クラス) を再度変更する必要があります。 COOKIE キーの値は気にしないでください)。
定数の使い方も悪く、Userクラスが定数設定に依存してしまう。
User クラス コンストラクターのパラメーターまたは配列を介してセッション名を渡す方が比較的良いですが、Session の保存方法が User クラスの内容ではないため、これは User クラス コンストラクターのパラメーターと干渉します。 User クラスを考慮する必要はありません。関連付けるべきではありません。
さらに、解決するのが簡単ではない別の問題があります。それは、SessionStorage クラスをどのように変更するかです。これには、テストにセッション シミュレーション クラスを使用する場合や、セッションをデータベースまたはメモリに保存する場合など、多くのアプリケーション シナリオがあります。現在の実装では、User クラスを変更せずにこれを行うことは困難です。
それでは、依存関係の注入を使用してみましょう。以前に User クラス内に SessionStorage オブジェクトを作成したことを思い出してください。ここで、それを変更し、User クラスのコンストラクターを介して SessionStorage オブジェクトを渡します。
class User { function __construct($storageOptions) { $this->storage = new SessionStorage($storageOptions['session_name']); } // ... } $user = new User(array('session_name' => 'SESSION_ID'));
これは、例外なく、依存性注入の最も典型的なケースです。 User クラスの使用にいくつかの小さな変更が加えられています。まず、SessionStorage オブジェクトを作成する必要があります。
class User { function __construct($storage) { $this->storage = $storage; } // ... }
これで、セッション ストレージ オブジェクトの設定は非常に簡単になり、セッション ストレージ オブジェクトの変更も非常に簡単になり、User クラスを更新する必要がないため、ビジネス クラス間の結合が軽減されます。
Pico Container の Web サイトでは、依存関係の注入について次のように説明されています。
依存関係の注入は、クラスのコンストラクター、メソッド、または直接記述を通じて依存コンポーネントをクラスに渡す方法です。
つまり、依存関係の注入はコンストラクターの注入に限定されません。いくつかの注入メソッドを見てみましょう:
コンストラクター注入
$storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
セッターメソッド注入
class User { function __construct($storage) { $this->storage = $storage; } // ... }直接属性注入
class User { function setSessionStorage($storage) { $this->storage = $storage; } // ... }
根据经验,一般通过构造函数注入的是强依赖关系的组件,setter方式用来注入可选的依赖组件。
现在,大多数流行的PHP框架都采用了依赖注入的模式实现业务组件间的高内聚低耦合。
// symfony: 构造函数注入的例子 $dispatcher = new sfEventDispatcher(); $storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session')); $user = new sfUser($dispatcher, $storage, array('default_culture' => 'en')); // Zend Framework: setter方式注入的例子 $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);
以上就是理解PHP依赖注入容器系列(一) 什么是的内容,更多相关内容请关注PHP中文网(www.php.cn)!