= せめてこれぐらいはやってほしいDI = DIというよりもサービスロケータですね、これは。 ともあれ、Springやシーサーのように(もともとは)貧弱な言語仕様のもとで無理やりDIを行おうとすると、その仕組み自体が面倒すぎる。 現在のphpの言語仕様の中で、「コメントの中にアノテーションを記述する」だの、「XMLを使ってワイヤリングする」だのするとかえって面倒なので、こういう場合は素直にサービスロケータを使った方がよい。 しかし「PHP サービスロケータ」としても全く検索結果が現れないのはどういうわけだろうか。 di.inc {{{ bindings[$interface] = $inst; } /** カレントのDIオブジェクトにインターフェース名とクラス名のバインドを設定する */ static public function bindClass($interface, $class) { assert(is_string($interface)); assert(is_string($class)); self::getCurrent()->bindings[$interface] = $class; } /** * インターフェース名からそのインスタンスを取得する * インスタンスがバインドされている場合はそのインスタンスを返す。 * クラスがバインドされている場合はそのクラスのインスタンスを生成して返す。 */ static public function get($interface) { $current = self::getCurrent(); @$binding = $current->bindings[$interface]; // インスタンスがバインドされている場合、それを返す。 if (is_object($binding)) { return $binding; } // 文字列がバインドされている場合、それをクラス名として新たなインスタンスを生成して返す。 if (is_string($binding)) { return new $binding(); } print "Binding of $interface not found"; assert(false); } } ?> }}} 上のテスト {{{ value; } } DI::bindClass('Test', 'TestImpl'); $test = DI::get('Test'); assert($test->test() == 1); DI::bindClass('Test', "TestMock1"); $test = DI::get('Test'); assert($test->test() == 2); $inst = new TestMock2(); DI::bindInst('Test', $inst); assert(DI::get('Test')->test() == 3); $inst->value = 4; assert(DI::get('Test')->test() == 4); ?> }}} GuiceのImplementedBy風に使うには以下。 {{{ DI::bindClass('Test', 'TestImpl') interface Test { } class TestImpl implements Test { } }}}