69

人々が依存性注入とその利点について話しているのをよく耳にしますが、私はそれをよく理解していません。

「データベース接続を常に引数として渡す」問題の解決策であるかどうか疑問に思っています。

ウィキペディアのエントリを読んでみましたが、例はJavaで書かれているため、明確にしようとしている違いがよくわかりません。( http://en.wikipedia.org/wiki/Dependency_injection )。

この依存性注入の PHP 記事 ( http://www.potstuck.com/2009/01/08/php-dependency-injection/ ) を読みましたが、オブジェクトに依存性を渡さないことが目的のようです。ただし、オブジェクトの作成とその依存関係の作成を禁止します。ただし、php関数を使用するコンテキストでそれを適用する方法がわかりません。

さらに、次の依存性注入はありますか?機能的なコンテキストで依存性注入を試みる必要がありますか?

バージョン 1: (私が作成する種類のコードですが、毎日好きではありません)

function get_data_from_database($database_connection){
    $data = $database_connection->query('blah');
    return $data;
}

バージョン 2: (データベース接続を渡す必要はありませんが、おそらく依存性注入は必要ありませんか?)

function get_database_connection(){
    static $db_connection;
    if($db_connection){
        return $db_connection;
    } else {
        // create db_connection
      ...
    }
}

function get_data_from_database(){
   $conn = get_database_connection();
   $data = $conn->query('blah');
   return $data;
}

$data = get_data_from_database();

バージョン 3: (「オブジェクト」/データの作成は別であり、データベース コードはそのままなので、おそらくこれは依存性注入としてカウントされるでしょうか?)

function factory_of_data_set(){
    static $db_connection;
    $data_set = null;
    $db_connection = get_database_connection();
    $data_set = $db_connection->query('blah');
    return $data_set;
}

$data = factory_of_data_set();

誰もが方法と利点を明確にする優れたリソースまたは単なる洞察を持っていますか?

4

5 に答える 5

76

依存性注入は、「コンストラクターにさらにいくつかのパラメーターがある」ことを表す大きな言葉です。

これは、グローバルが好きではなかったときに、ひどいシングルトンの波の前にあなたがしたことです:

<?php
class User {
    private $_db;
    function __construct($db) {
        $this->_db = $db;
    }
}

$db   = new Db();
$user = new User($db);

さて、トリックは、依存関係を管理するために単一のクラスを使用することです。

class DependencyContainer 
{
    private _instances = array();
    private _params = array();

    public function __construct($params)
    {
        $this->_params = $params;
    }

    public function getDb()
    {
        if (empty($this->_instances['db']) 
            || !is_a($this->_instances['db'], 'PDO')
        ) {
            $this->_instances['db'] = new PDO(
                $this->_params['dsn'],
                $this->_params['dbUser'], 
                $this->_params['dbPwd']
            );
        }
        return $this->_instances['db'];
    }
}

class User
{
    private $_db;
    public function __construct(DependencyContainer $di)
    {
         $this->_db = $di->getDb();
    }
}

$dependencies = new DependencyContainer($someParams);
$user = new User($dependencies);

あなたはただ別のクラスであり、より複雑であると考えなければなりません。ただし、ユーザー クラスには、他の多くのクラスと同様に、メッセージをログに記録するための何かが必要になる場合があります。getMessageHandler 関数を依存関係コンテナーに追加し、いくつか$this->_messages = $di->getMessageHandler()をユーザー クラスに追加するだけです。コードの残りの部分を変更する必要はありません。

symfony のドキュメントで多くの情報を得ることができます

于 2010-03-31T14:48:07.270 に答える
14

最初の例は依存性注入です。データベース オブジェクトへの依存性を関数に注入しています。

サラはそうではないと言いましたが、そうです、彼女は次のレベルの依存性注入コンテナーを考えていると思います:

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers

于 2010-03-31T14:19:28.933 に答える
6

あなたの例はどれも依存性注入のようには見えませんが、バージョン1が最も近いです。依存性注入は、オブジェクト指向プログラミングで使用される手法であり、オブジェクトのコンストラクターには必要なサービスオブジェクトの引数があり、それらのサービスオブジェクトはインスタンスの作成者(ファクトリ、テスト、または依存性注入フレームワーク)。

'常に接続オブジェクトを渡す'問題を回避するには、テンプレートパターンを検討することをお勧めします。テンプレートパターンは、基本的に、繰り返されるコードブロックの共通部分と、それらの繰り返されるコードブロックのインスタンス間のバリエーションを可能にする抽象メソッドを備えた抽象基本クラスです。基本的に、ベースはコードブロックのテンプレートであり、抽象メソッドは埋められる空白です。私は個人的にテンプレートメソッドパターンを使用して、Javaでデータベースリソースを制御します。

于 2010-02-13T00:19:22.587 に答える
2

私はこのトピックについて自分で多くの検索を行いましたが (PHP 依存性注入)、私の好みに合うものはあまり見つかりませんでした。このテーマについては、他の言語 (Google Guice - http://code.google.com/p/google-guice/ ; Java Spring) について多くのことが書かれていますが、PHP についてはあまり利用できませんでした。ただし、言語に関係なく、課題は似ています。

質問に記載されている 3 つのバージョンは、典型的なアプローチです。バージョン 3 は、私が見てきた業界の方向性に最も近いものです。依存オブジェクトを作成する責任をクラス外に移すことで、テスト コードで好きなようにオブジェクトを操作できます。ただし、このアプローチで私が遭遇した問題は、コンストラクター内に依存オブジェクトの長いチェーンができてしまい、受信オブジェクトによって使用されることさえありませんが、二次依存オブジェクトに渡される可能性があることです。ぐちゃぐちゃになり、何がどこから来ているのかわからなくなります。

@Arkh と @mmmshuddup による Dependency Container の例は素晴らしい出発点ですが、それでもそのアプローチにも限界があることがわかりました。私がたどり着いた最終的なソリューションは、Scala で人気のある Cake パターンをモデルにしたカスタム ビルドのソリューションでした。各コンストラクターに単一の依存関係を渡すことができ、クラスごとに依存オブジェクトのデフォルトの構築を定義できます。これにより、依存関係の長いチェーンから解放され、依存関係のデフォルトの実装を制御できなくなります。

私はそのシステムをディーゼルと呼びましたが、とても満足しています。興味のある方のために、コードを github で公開しました。この件について私が書いたブログからアクセスできます。このブログでは、基本的な使用方法が説明されており、質問の詳細が説明されています。http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/

于 2012-04-02T18:59:55.770 に答える
2

依存性注入は、2 つのコンポーネント間の依存関係を削除して、それらが依存している理由に注目するという考え方です。

別のコンポーネント B のサービスを使用する必要があるコンポーネント A があるとします。

A 内に B の存在をハードコーディングすると、A に同じサービスを使用させたいが別のコンポーネントで実装したい場合に行き詰まります。

したがって、通常、B と C が実装するサービス インターフェイスを定義し、A を使用するときに、必要なインターフェイスと互換性のあるオブジェクトを A に供給するようにします。

あなたの場合、インターフェースはクエリを実行できるサービスであると考えるかもしれません。

あなたの最初のケースは、依存性注入のアイデアに近いものです。

于 2012-06-07T22:45:21.210 に答える