2

タイトルが私が求めているものについて多くの手がかりを与えていないことを私は知っているので、ここに単純化された状況があります:

class MyPDO extends PDO
{
    private $stmt;

    function __construct($dsn...)
    {
        parent:__construct($dsn...);
    }

    function myQuery($sql)
    {
        $this->stmt = $this->query($query);
    }

    function myFetchAll()
    {
        return $this->stmt->fetchAll($mode);
    }

    function myFetchRow()
    {
        return $this->stmt->fetch();
    }

}

アプリケーション全体で、MyPDOのベースインスタンスがあり、それをさまざまなオブジェクト、マッパーに渡します。

$adapter = new MyPDO($dsn...);
$adapter->myQuery('SELECT * FROM table');
$rows = $adapter->myFetchAll();

$another_object = new ObjectThatNeedsPDO($adapter);
$another_object->adapter->myQuery('SELECT * from another_table');
$rows = $another_object->adapter->myFetchAll();

このアプローチは、特にMyPDO :: stmtの観点から安全ですか?アプリケーションフローが混乱して、予想よりも別の$ stmtからデータをフェッチしてしまう可能性はありますか?

4

3 に答える 3

2

個人的には、私はあなたのアプローチを取りません。その理由は、あるクラスによって作成されたステートメントオブジェクトが別の無関係なクラスに公開される可能性を望まないためです。さらに、実装クラスごとに、実行する必要のあるさまざまな種類のパラメーターバインディング、データにアクセスする必要のある方法(つまり、すべての行をフェッチする、各行をフェッチする、オブジェクトとしてフェッチするか配列としてフェッチするなど)、クラス固有の方法でエラーを処理する方法など。

私にとって、基本PDOクラスの子の中にこのロジックを含めることによって何も得られません。つまり、実行するのは本当に難しいということです。

$stmt = $this->pdo->query(...)
$data = $stmt->fetchAll();

よりも:

$this->myPDO->query(...);
$data = $this->myPDO->myFetchAll();

この追加クラスを、それを消費するすべてのクラスに不必要に結合する以外に、何が得られますか?実際、ステートメントの相互作用は常にクラス固有であり、基本PDOインスタンスによって提供される唯一の共通機能(DB接続)があります。

そのため、クラス間で共通のPDOインスタンスを自由に渡すことができます。これは、間違いなく良い方法です(つまり、依存性注入)。

提案されたmyPDOクラスに変更を加えるときに、すべての実装クラスを変更する可能性があるのか​​、それとも、実装クラスがステートメントオブジェクトと対話するためのカスタム手段を必要とするたびにmyPDOクラスを変更するのかについて、真剣に考えてください。

以下の説明に基づいて、最大限の柔軟性を提供するためにPDOStatementを拡張することを検討することをお勧めします。

これは次のようになります。

class myPDOFactory {
    public static function getInstance($dsn, $pdo_statement_class = 'myPDOStatement', $pdo_constructor_args = NULL);
        $pdo = new PDO($dsn);
        if (empty($pdo_statement_class)) {
            $pdo_statement_class = 'PDOStatement';
        }
        if (empty($pdo_constructor_args) || !is_array($pdo_constructor_args)) {
            $pdo_constructor_args = array();
        }
        $config_array = array($pdo_statement_class, $pdo_constructor_args);
        $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, $config_array);
        return $pdo;
    }
}

class myPDOStatement extends PDO Statement {
    public function __construct(<any custom parameters you may need to have passed - items in $pdo_constructor_args from myPDOFactory class>) {
        parent::__construct();
        // any special stuff you want to do with any passed parameters here
    }

    public function fetchAll() {
        // override any functionality you desire here
    }

    public function fetchAllObjects() {
        return $this->fetchAll(PDO::FETCH_OBJ);
    }
}

class someClassThatNeedsPDO {
    protected $pdo = NULL;
    public function __construct($pdo) {
        if($pdo instanceof PDO) {
            $this->pdo = $pdo;
        } else {
            throw new Exception('Ooops!');
        }
    }

    public function doSomethingWithPDO() {
        $stmt = $this->PDO->prepare('SELECT * FROM sometable');
        $stmt = execute();
        return $stmt->fetchAllObjects();
    }
}

使用例:

$pdo = myPDOFactory::getInstance($dsn, 'myPDOStatement', $constructor_args);
$consuming_class = new someClassThatNeedsPDO($pdo);
$object_array = $consuming_class->doSomethingWithPDO();  
于 2013-01-07T20:37:42.617 に答える
1

あなたのアプローチは不必要な妨害の層のように見えますが、これはうまくいくはずです。fetchネイティブのfetch/fetchallを呼び出す前に、メソッドにチェックを追加して、有効なPDOステートメントが存在することを確認します。

また、すべてのMyPDOオブジェクトに対して新しい接続を作成しないことをお勧めします。PDO接続を渡します。

于 2013-01-07T20:37:15.437 に答える
0

PDO(および以前はmysqliラッパー)を処理するときは、常にシングルトンパターンを使用します。つまり、インスタンスは1つだけであり、他のクラスに渡す必要はありません。あなたがそれをしている方法は大丈夫で安全ですが、シングルトンを使用する方が良いです。

シングルトンの作成は本当に簡単です。

class myClass{
    private static $instance;

    public static function singleton()
    {
        if (!self::$instance) {
            return self::$instance = new myClass();
        } else {
            return self::$instance;
        }       
    }

    public static function myQuery($query)
    {
        #Do stuff
    }
}

インスタンスを作成するときは、次のように呼び出します。

myClass::singleton()

そして、メソッドを使用したい場合は、これを使用してください。

myClass::myQuery($query)

名前空間を使用している場合は、完全修飾名を使用する必要があります(例:my \ namespace \ myClass)

それが理にかなっていることを願っています!

于 2013-01-07T20:45:51.933 に答える