4

依存性注入に基づいて、PHP フレームワークを開発しています。私のデータ オブジェクトは、他のオブジェクトと同様に、注入可能なコンポーネントです。

各モデルを拡張する必要がある抽象DAOクラスがあります。

  • 基本的なクラッドメソッド
  • オブジェクトをインスタンス化するための DI コンテナーへの参照

物事は、要するに、このようなものです

abstract class AbstractDao {
  protected $fields;
  protected $container; // This is the (injected) DI container, used to create instances.
  protected $driver; // The injected database driver (i.e. PDO)
  public function insert() {
    // Insert implementation
    // Insert current instance.
  }
  public function fetch($id) {
    // Fetch implementation
    // Fetches a row and sets fields on current instance
  }
  public function fetchAll() {
    // Performs a select * query on database driver
    // Iterates through results, and creates an instance
    // for each result using $container, like this:
    foreach ($results as $row) {
      // I can't just make $instances[] = new Something(), or all the
      // dependency injection thing would mess up.
      $instances[] = $this->container->get('someDao');
    }
    return $instances;
  }
  // Other methods.
}

class Book extends AbstractDao {
  protected $fields = array('field', 'definition', 'goes', 'here',);
  // No special behaviour is needed, so we can keep default
  // abstract implementation without overriding.
}

私の質問: すべてのデータ オブジェクトの実装 (本、人物、ユーザーなど) は、AbstractDao オブジェクトを拡張する必要があるため、 $driver と $containerの重量を運ぶことになります。さらに、$fields プロパティはインスタンス レベルで定義されるため、各データ オブジェクトには独自のデータ オブジェクトがあり、オーバーヘッドが追加されます。

大きなデータセットを処理する場合、このソリューションはパフォーマンスの点で非常に高価なものになるのではないかと心配しています. オブジェクトが参照されるだけで、複製されないことはわかっていますが、オーバーヘッドが悲しいほど高くなる可能性があります。

私が念頭に置いているいくつかの解決策は

  • サブクラスのオーバーヘッドを削減できる静的メソッドの実装を使用する
  • 私のDaosが上記のAbstractDaoを拡張しないようにしてください。これは一種のDaoProviderになるはずです。この場合、メソッドごとに、インスタンスを渡す必要があります (これはあまり好きではありません)。

これらのソリューションのどれも私がそれほど好きではありません...最初に、静的なものを使用するのは好きではありません。第二に、dao のサブクラス化パターンを削除するという考えは好きではありません。

良いアイデアをいただければ幸いです。

=== 編集 ===

ふと気になったことがもう一つ。2番目のアプローチ(「daoプロバイダー」)で気に入らないのは、プロバイダーがDaoフィールドで操作(値の設定、ステータスの設定、isDirtyの設定など)を実行する必要があるため、フィールドを外部からアクセスできるようにする必要があることです。 . サブクラス化アプローチを使用すると、それらを保護またはプライベートに保つことができます。

=== /編集 ===

4

1 に答える 1

2

DAO実装が定義する必要のある動作を宣言するDAOインターフェースを作成することをお勧めします。これで、各具体的なDAO実装$driverで、$containerおよび$fieldsインスタンスフィールドを定義できます。

その後、AbstractModel各具象モデルを拡張してAbstractModel、具象モデルと具象モデルの両方が「データアクセスにとらわれない」ようにするクラスを作成することをお勧めします。クラスは次のAbstractModelようになります。

/*
* an AbstractModel
*/
abstract class AbstractModel {

    protected $daoImpl;

    function __construct(DAOInterface $daoImpl) {
        $this->daoImpl = $daoImpl;
    }

    //some other functions that are common to concrete models
}

/*
* a concrete model
*/
class Model extends AbstractModel {

    function findAll($params) {
        //You can use the $daoImpl of AbstractModel to perform a CRUD operation
        $this->daoImpl->findAll($params);
    }

}

これで、具象モデルをインスタンス化するたびに、DAO実装をモデルクラスに注入します。

//inject a DAOInterface implementation into Model
$model = new Model(new DAOImpl());
$model->findAll($params);

ここでの利点は、テスト中にさまざまなDAO実装をスタブできることです。おそらく、これがDIコンテナーが役立つ場所です。数日前にDIコンテナを作成していたときに作成した同様のコードサンプルがあります。

ところで$container、AbstractDAO内にオブジェクトを配置する必要はないと思います。コンテナのプロパティを呼び出したときに返されるオブジェクトを渡してみませんか。そうすれば、タイプヒント$driverを使用して、オブジェクトパラメータを特定のタイプにすることができ、間違ったオブジェクトが渡された場合にフェイルファストメカニズムを促進できます。また、詳細を処理するConfigクラスを作成して、ユーザーは、データベースに使用するドライバーを自由に構成できます。

于 2013-03-04T08:50:31.130 に答える