2

以下に、接続が 1 つしかない場合にデータベース アクセスを簡素化するための 3 つのオプションを示します (これは、私が取り組んでいる Web アプリの場合によくあります)。

一般的な考え方は、スクリプトが最初にクエリを実行したときに接続し、スクリプトが終了するまで接続を維持するように、DB 接続を透過的にすることです。

どれが一番良いと思うか、その理由を知りたいです。これらに適合する可能性のあるデザインパターンの名前がわからないので、使用しないで申し訳ありません。また、PHP5 でこれを行うためのより良い方法があれば、共有してください。

簡単に紹介すると、クエリ メソッドを含む DB_Connection クラスがあります。これは、私が制御できないサードパーティ クラスであり、この例の目的のためにインターフェイスを単純化しました。各オプションでは、状況を説明するために架空の DB「アイテム」テーブルのモデル例も提供しました。

オプション 3 は、私が最も気に入っているインターフェイスを提供してくれるものですが、残念ながら実用的ではないと思います。

以下のコメント ブロックで、それぞれの長所と短所 (私が見ることができる) について説明しました。

現時点では、モデルではなく DB ラッパー クラスに負担がかかるため、オプション 1 に傾いています。

すべてのコメントに感謝します!

注: 何らかの理由で、スタック オーバーフロー プレビューにアンダースコアではなく、エンコードされた HTML エンティティが表示されます。投稿がそのように通過する場合は、これを考慮してください。

<?php

/**
 * This is the 3rd-party DB interface I'm trying to wrap.
 * I've simplified the interface to one method for this example.
 *
 * This class is used in each option below.
 */
class DB_Connection {
    public function &query($sql) { }
}

/**
 * OPTION 1
 *
 * Cons: Have to wrap every public DB_Connection method.
 * Pros: The model code is simple.
 */
class DB {
    private static $connection;
    private static function &getConnection() {
        if (!self::$connection) {
            self::$connection = new DB_Connection();
        }
        return self::$connection;
    }
    public static function &query($sql) {
        $dbh = self::getConnection();
        return $dbh->query($sql);
    }
}

class Item {
    public static function &getList() {
        return DB::query("SELECT * FROM items");
    }
}

/**
 * OPTION 2
 *
 * Pros: Don't have to wrap every DB_Connection function like in Option 1
 * Cons: Every function in the model is responsible for checking the connection
 */

class DB {
    protected static $connection = null;
    public function connect() {
        self::$connection = new DB_Connection();
    }
}

class Item extends DB {
    public static function &getList() {
        if (!self::$connection) $this->connect();
        return self::$connection->query("SELECT * FROM items");
    }
}

/**
 * OPTION 3
 *
 * Use magic methods
 *
 * Pros: Simple model code AND don't have to reimplement the DB_Connection interface
 * Cons: __callStatic requires PHP 5.3.0 and its args can't be passed-by-reference.
 */
class DB {
    private static $connection = null;

    public static function &getConnection() {
        if (!self::$connection) {
            self::$connection = new DB_Connection();
        }
        return self::$connection;
    }

    public static function __callStatic($name, $args) {
        if (in_array($name, get_class_methods('DB_Connection'))) {
            return call_user_func_array(
                array(self::getConnection(), $name), $args);
        }
    }
}
4

2 に答える 2

1

上記の例に基づいて、オプション1が最適だと思います-シンプルさが常に勝ち、方法に応じて失敗した接続を異なる方法で処理できます(ストアドプロシージャ呼び出しでは、単純なSELECTとは異なる方法で失敗する場合があります。実例)。

于 2008-09-10T03:15:24.127 に答える
1

意味的に言えば、オプション1が最も理にかなっていると思います.DBをリソースとして扱っている場合、DB_Connectioinはそれが使用するオブジェクトですが、必ずしもオブジェクト自体ではありません.

ただし、注意すべき点がいくつかあります。まず、コードをテストする能力に大きな影響を与えるため、DB クラスにすべての静的メソッドを持たせないでください。代わりに、次のようなコントロール コンテナーの非常に単純な反転を考えてみましょう。

class DB {
    private $connection;
    public function &query($sql) {
        return $connection->query($sql);
    }
    public __construct(&$db_connection) {
        $this->connection = $db_connection;
    }
}

class Item {
    public function &getList() {
        return  ResourceManager::getDB()->query("SELECT * FROM items");
    }
}

class ResourceManager {
    private $db_connection;
    private function &getDbConnection() {
        if (!$this->connection) {
            $this->connection = new DB_Connection();
        }
        return $this->connection;
    }
    private $db;
    public static function getDB() {
        if(!$this->db) $this->db = new DB(getDbConnection());
    return $this->db;
}

大きな利点があります。DB をシングルトンとして使用したくない場合は、ResourceManager を 1 つ変更するだけです。シングルトンではないと判断した場合は、1 か所で変更を行います。何らかのコンテキストに基づいて DB の別のインスタンスを返したい場合、変更は 1 か所だけです。

DB を分離して Item をテストしたい場合は、ResourceManager で setDb($db) メソッドを作成し、それを使用してフェイク/モック データベースを設定します (その点ではsimplemockが役立ちます)。

2 つ目 - これは、この設計が容易になるもう 1 つの変更点です。データベース接続をずっと開いたままにしておくのは望ましくないかもしれません。必要以上に多くのリソースを使用してしまう可能性があります。

最後に、DB_Connection には表示されていない他のメソッドがあるとおっしゃっているように、単に接続を維持する以上の目的で使用されているようです。あなたはそれを制御できないと言っているので、あなたが気にかけているメソッドからインターフェースを抽出し、 MyDBConnection を作成して、インターフェースを実装する DB_Connection クラスを拡張することをお勧めします。私の経験では、そのようなことは最終的にはいくらかの痛みも和らげます.

于 2008-09-10T11:48:50.477 に答える