2013-01-29

PDOのプリペアドステートメントで同じ名前のパラメータマーカは使えない

PDOでプリペアドステートメントを使うとき、クエリ中にパラメータマーカを指定するが、このとき、同じ名前のパラメータマーカは使えない。
でも、使ってもエラーにならない。

クエリの結果を精査すれば、クエリで想定した結果にならないためわかるのだが、テストが嫌いな俺は、クエリそのものを検査することにした。

//  すべてのパラメータマーカを取得する。
preg_match_all('/(:[\w]+)/', $sql, $matches);

//  パラメータマーカの出現回数を得る。
$param = array_count_values($matches[1]);

//  2回以上出現したパラメータマーカを調べる。
foreach($param as $key => $val) {
  if($val > 1) {
    echo "パラメータマーカ {$key} を {$val} 個検出しました。";
    //  ここでエラーを発生させるか、強制終了する。
  }
}

こんな感じのロジックをPDOを継承したクラスに仕込んでおけばOK。

class dao extends PDO
{
    const DAO_ERROR_PARAMETER_MARKER_DUPLICATED = 777;

    //  今回必要なところだけ記述
    public function prepare($statement, $options = array())
    {
        preg_match_all('/(:[\w]+)/', $sql, $matches);
        $param = array_count_values($matches[1]);
        foreach($param as $key => $val) {
            if($val > 1) {
                //  エラーモードに応じて、例外を発生させるか、falseを返す。
                $err_mode = $this->getAttribute(PDO::ATTR_ERRMODE);
                if($err_mode === PDO::ERRMODE_EXCEPTION) {
                    throw new Exception("パラメータマーカ {$key} を {$val} 個検出しました。"
                                      , self::DAO_ERROR_PARAMETER_MARKER_DUPLICATED);
                }
                else {
                    return false;
                }
            }
        }
        return parent::prepare($statement, $options);
    }
}

0 件のコメント:

コメントを投稿

Toとccの使い分け

 入社3年目の女性社員がメールを書いていた。 Toに10人ぐらい入っていた。 メール本文の宛名は2名。 「このメールは、Toに宛名の2名、あとはccに入れて送るのが基本」 って教えたけど 「え、Outlookでアドレスグループ作って宛名に入れると、全部展開されてこうなるんですけど...