64

私の理解:

  • 依存関係とは、ClassA のインスタンスが、ClassA の新しいインスタンスをインスタンス化するために ClassB のインスタンスを必要とする場合です。
  • 依存性注入は、ClassA のコンストラクターのパラメーターまたは set~DependencyNameHere~(~DependencyNameHere~ $param) 関数を介して、ClassA が ClassB のインスタンスを渡される場合です。(これは、私が完全に確信していない分野の 1 つです) .
  • IoC コンテナーは、このプロジェクトのクラスのオブジェクトをインスタンス化する特定の方法を登録できるシングルトン クラスです (一度に 1 つのインスタンスのみをインスタンス化できます)。これは、私が使用してきた IoC コンテナーのクラス定義とともに、説明しようとしているものの例へのリンクです。

したがって、この時点で、より複雑なシナリオで IoC コンテナーの使用を試み始めます。現時点では、IoC コンテナーを使用するために、IoC コンテナーで定義したい依存関係を持つ、作成したいほとんどすべてのクラスの has-a 関係に制限されています。クラスを継承するクラスを作成したいが、親クラスが IoC コンテナーに登録された特定の方法で作成されている場合に限ります。

例: mysqli の子クラスを作成したいのですが、このクラスを IoC コンテナーに登録して、以前に IoC コンテナーに登録した方法で構築された親クラスでのみインスタンス化したいと考えています。コードを複製せずにこれを行う方法は考えられません (これは学習プロジェクトであるため、可能な限り「純粋」に保とうとしています)。ここに、私が説明しようとしているものの例をいくつか示します。

だからここに私の質問のいくつかがあります:

  • OOPの原則を破ることなく、私がやろうとしていることは可能ですか? 私はC ++で動的メモリとコピーコンストラクタを使用してそれを達成できることを知っていますが、phpでそのような機能を見つけることができませんでした. (私は __construct 以外の他の魔法のメソッドを使用した経験がほとんどないことを認めますが、正しく理解していれば、読み取りと __clone から、コンストラクターでそれを使用して、インスタンス化されている子クラスをインスタンス化することができませんでした。親クラスのインスタンス)。
  • すべての依存関係クラスの定義は、IoC に関連してどこに行く必要がありますか? (私の IoC.php の上部には、require_once('dependencyClassDefinition.php') がたくさんあるはずですか?私の直観的な反応は、もっと良い方法があるということですが、まだ思い付いていません)
  • オブジェクトをどのファイルに登録する必要がありますか? 現在、クラス定義の後に IoC.php ファイルで IoC::register() へのすべての呼び出しを実行しています。
  • 依存関係を必要とするクラスを登録する前に、IoC に依存関係を登録する必要がありますか? IoCに登録されたオブジェクトを実際にインスタンス化するまで匿名関数を呼び出していないので、そうではないと思いますが、それでも懸念事項です。
  • 私が見落としている、または使用する必要があるものは他にありますか? 私は一度に一歩ずつ進めようとしていますが、私のコードが再利用可能になること、そして最も重要なこととして、私のプロジェクトについて何も知らない人がコードを読んで理解できることも知りたくありません。
4

1 に答える 1

134

簡単に言えば (これは OOP の世界だけに限定された問題ではないため)、依存関係とは、コンポーネント A がコンポーネント B に必要な (依存する) 必要がある (依存している) 状況です。この単語は、このシナリオで依存するコンポーネントを説明するためにも使用されます。これを OOP/PHP 用語で表現するには、次の例を必須の車のアナロジーで考えてみましょう。

class Car {

    public function start() {
        $engine = new Engine();
        $engine->vroom();
    }

}

Car に依存Engineます。Engine依存関係Carです。ただし、このコードはかなり悪いです。理由は次のとおりです。

  • 依存関係は暗黙的です。Carのコードを調べるまで、そこにあることはわかりません
  • クラスは密結合です。テスト目的Engineでを置き換えることはできません。また、 を変更せずに元のものを拡張することもできません。MockEngineTurboEngineCar
  • 自動車がエンジンを自作できるなんて、ばかげているように見えませんか?

依存性注入Carは、必要な事実をEngine明示的にし、それを明示的に提供することで、これらすべての問題を解決する方法です。

class Car {

    protected $engine;

    public function __construct(Engine $engine) {
        $this->engine = $engine;
    }

    public function start() {
        $this->engine->vroom();
    }

}

$engine = new SuperDuperTurboEnginePlus(); // a subclass of Engine
$car = new Car($engine);

上記はコンストラクター注入の例であり、依存関係 (依存先オブジェクト) がクラス コンストラクターを介して依存関係 (コンシューマー) に提供されます。setEngine別の方法は、Carクラスでメソッドを公開し、それを使用して のインスタンスを注入することですEngine。これはセッター注入として知られており、主に実行時にスワップされるはずの依存関係に役立ちます。

自明ではないプロジェクトは、相互に依存する多数のコンポーネントで構成されており、何がどこに注入されるかをすぐに把握できなくなります。依存性注入コンテナーは、他のオブジェクトをインスタンス化および構成する方法を認識し、プロジェクト内の他のオブジェクトとの関係を認識し、依存性注入を行うオブジェクトです。これにより、すべてのプロジェクトの (相互) 依存関係の管理を一元化でき、さらに重要なことに、コード内の多数の場所を編集することなく、それらの 1 つまたは複数を変更/モックできるようになります。

車のアナロジーを捨てて、例として OP が達成しようとしていることを見てみましょう。Databaseオブジェクトに依存するオブジェクトがあるとしましょうmysqli。与えられた名前でオブジェクトを作成する方法を登録する方法と、その名前からオブジェクトを取得する方法のDIC2 つのメソッドを公開する、非常にプリミティブな依存関係検出コンテナー クラスを使用するとします。コンテナのセットアップは次のようになります。register($name, $callback)resolve($name)

$dic = new DIC();
$dic->register('mysqli', function() {
    return new mysqli('somehost','username','password');
});
$dic->register('database', function() use($dic) {
    return new Database($dic->resolve('mysqli'));
});

のインスタンスをアセンブルするために、コンテナmysqli 自体からのインスタンスを取得するようにコンテナに指示していることに注意してくださいDatabase。次にDatabase、依存関係が自動的に注入されたインスタンスを取得するには、次のようにします。

$database = $dic->resolve('database');

それが要点です。やや洗練されていますが、それでも比較的シンプルで把握しやすい PHP DI/IoC コンテナーはPimpleです。その他の例については、ドキュメントを確認してください。


OPのコードと質問について:

  • コンテナ(またはそれ以外のもの)に静的クラスまたはシングルトンを使用しないでください。彼らは両方とも悪です。代わりににきびをチェックしてください。
  • mysqliWrapperクラスを拡張する mysqlか、それに依存するかを決定します。
  • IoC内部から呼び出すことにより、mysqliWrapperある依存関係を別の依存関係に交換しています。オブジェクトはコンテナを認識したり使用したりしてはなりません。それ以外の場合は、DIC ではなく、Service Locator (アンチ) パターンです。
  • requireそのクラスのオブジェクトを使用するかどうかはまったくわからないため、コンテナーに登録する前にクラス ファイルを作成する必要はありません。すべてのコンテナのセットアップを 1 か所で行います。オートローダーを使用しない場合はrequire、匿名関数内でコンテナーに登録できます。

その他のリソース:

于 2013-09-02T00:44:53.930 に答える