読者です 読者をやめる 読者になる 読者になる

わざわざ残す必要もないことを整理とか気にせずに吐き出していく。そんな空間。

PHPでDIする話

PHPで(クラスレベルの)依存性注入を考えるとき、思いつくだけでもざっとこれくらいはやり方がある。

Twitterとかで色々やりとりがあったので、とりあえず自分の現状把握してるメリット・デメリットまとめていきたい。

DIコンテナを使う

多くのフレームワークで使われている手法、なわけですがいまいちメリットがわからない。

まず、コンテナから取り出したオブジェクトの型が直感的にわからない。 コンテナにオブジェクトごとの専用GetterがあればDocコメントの@returnアノテーションが教えてくれるけど コンテナは可変長マップだからそんなことはやってられないわけで。

Symfonyみたいな有名なフレームワークになると専用のプラグインが提供されてたりもして、 IDEの恩恵も受けれるみたいですが、そういうのはコミュニティが成熟しきってこそできるわけで。

そして、オブジェクトしか注入できないという点。クラスのstaticな機能が完全に殺されてしまう。 static使うな、とかいう声も聞こえてくるかもですが、PHPのstaticはかなり使いやすいと思うのです。

結局、DIコンテナに依存することになるので、アプリケーション全体の動きを把握したい場合には、ユーザはDIコンテナに何が登録されているのか、について意識する必要がでてきます。つまり全体の挙動はコンテナに依存するという事になります。

ただ、高機能なDIコンテナは、シングルトン/マルチトンの制御を行ってくれたりするかもしれません。 こういった機能は便利ですが、クラス側で行うことも可能ですし、複雑なコンテナはコンテナに対する理解をより難しくするかもしれません。

オートローダを使う

みんな大好きFuelPHPで実装されている方法です。

オートローダを使ったDIはDIコンテナを使った方法にかなり似ています。 どちらも内部的にはマップを用いたエイリアスによるデータの取り出しなのですが、 DIコンテナエイリアスの先にオブジェクトをひもづけるのに対して、 オートローダではエイリアスの先にクラス名を紐付けて、クラスエイリアスによるDIを提供します。

これにより、オートローダの設定以外で、コード上においてDIを意識する必要はなくなります。 DIのようにコンテナからオブジェクトを取り出す必要もなく、単にエイリアスクラス名を用いてコードを記述すれば、依存関係はオートローダが自動的に解決してくれます。

また、クラス名を用いたコード記述になるのでstaticな範囲においてもDIが適用できます。

IDEサポートにおいても複雑なプラグインを実装する必要はなく、例の_ide_helper.phpを作成するだけで補完を実現することが可能になる点も優しい作りといえると思います。

なおこの場合、「同一のクラスに対して、複数のクラス名が定義される」ため、クラスコールの方法については統一した実装ルールを決めておく必要があると思います。

また、コンテナに変わってオートローダにDIが依存する形になるため、オートローダに何が登録されているのかについて把握しなければならない、という問題も結局変わりません。

コンストラクタ注入

コンストラクタ注入のスタイルは、DIをかなりきれいな形で実現してくれます。聞いたところによると、PHP-DIにおいてもベスト・プラクティスとして扱われているようです。

コンストラクタ注入(とインターフェイス&タイプタイプヒンティング)によるスタイルは、 特別な仕組みを用いて実装されるわけでもなく、言語の基本的な構文を用いて実装されるため、 理解しやすくIDEの恩恵も受けやすいという一方で、記述はかなり煩雑になります。

注入しようとするオブジェクトの数に応じて、煩雑さは増大し、コンストラクタも見難くなっていきますし、 newしようとするコードの記述やnewに必要なオブジェクトの準備なども煩雑になって行きます。

PHP-DIなどのライブラリでは、リフレクションを用いて、コンストラクタの記述を省略したり、 オブジェクト生成の際の手続きを省略したりできるようにしているみたいですが、 そこまでやりだすとなんか違うんじゃね?みたいな気持ちになってきます。

結論

基本的にはコンストラクタ注入かなぁと思うのですが、規模が膨らむとどう考えてもまかないきれないので、 なんらかのDIの仕組みに依存するのは必須だと思います。

その中でPHP-DIか、オートローダか、DIコンテナかという選択になれば私は間違いなくオートローダを選ぶと思うのです。 リフレクション系のPHP-DIは一旦おいといて、オートローダとDIコンテナとを比べた時に、 DIコンテナの方にメリットを全く見いだせないというのが現状で。

staticはとりあえず置いとくにしても、プラグインを使えば欠点解消できるよ、というのは解決策としてなんというか釈然としない、開発スタイルが プラグインに依存するというのも嫌だし…というモヤモヤした気持ちでいっぱいになってしまうのです。

何が言いたいかというと、Fuel2.0、どうしてそうなった。ということです。