web-dev-qa-db-ja.com

単純なphp関数で「依存性注入」を使用するにはどうすればよいですか?

依存関係の注入とその利点について人々がいつも話しているのを聞きますが、実際には理解していません。

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

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

私はこのdependency-injection-in-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();

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

67
Kzqai

依存性注入は、「コンストラクターにいくつかのパラメーターがあります」の大きな言葉です。

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

_<?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のドキュメント で多くの情報が得られます

75
Arkh

最初の例[〜#〜] is [〜#〜]依存性注入、データベースオブジェクトへの依存性を関数に注入しています。

サラはこれはそうではないと言っていますが、そうではありませんが、彼女は次のレベルの依存性注入コンテナを考えていると思います。

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

13
jmoz

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

「常に接続オブジェクトを渡す」問題を回避するには、テンプレートパターンを検討する必要があります。テンプレートパターンは、基本的に、繰り返されるコードブロックの共通部分と、繰り返されるコードブロックのインスタンス間のバリエーションを可能にする抽象メソッドを持つ抽象基本クラスです。基本的に、ベースはコードブロックのテンプレートであり、抽象メソッドは入力する空白です。個人的にテンプレートメソッドパターンを使用して、Javaでデータベースリソースを制御します。

7
Sarah Happy

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

質問にリストする3つのバージョンは、典型的なアプローチです。バージョン3は、業界が進む方向に最も近い方向です。クラスの外部で依存オブジェクトを作成する責任をシフトすることにより、テストコードで自由に操作できます。ただし、このアプローチで私が遭遇した問題は、コンストラクター内の依存オブジェクトの長いチェーンになり、受信オブジェクトが使用することさえできず、セカンダリ依存オブジェクトに渡される可能性があることです。面倒になり、どこから来ているのかが分からなくなります。

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

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

2
Ben

依存性注入は、2つのコンポーネントが依存関係にある理由に焦点を当てるために、2つのコンポーネント間の依存関係を削除するという考え方です。

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

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

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

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

最初のケースは、依存性注入の概念に近いケースです。

2
Jerome WAGNER