LoginSignup
4
2

More than 5 years have passed since last update.

PHPのPDOStatement::bindParamでハマったメモ

Posted at

ヽ(`@A@´#)ノ ムキー!!

前提

久しぶりにフレームワークの入らないPHPを書きました。
$_POSTで受け取ったデータをDBに書き込むだけの簡単なお仕事です。

    function insert($dto){
        $sql = 'insert into '.TABLE.'('.implode(',',DTO::get_insert_key()).') values ('.implode(',',DTO::get_insert_holder()).')';
        $stmt = $this->pdo->prepare($sql);

        foreach(DTO::get_insert_holder() as $holder){
            $key=substr($holder,1); // ※ここは単に:取り除いてるだけ
            $val=$dto->get($key);
            $b=$stmt->bindParam($holder ,$val);
        }

        $stmt->execute();
    }

※DTO::get_insert_keyはDBのカラム名を配列で、get_insert_holderはカラム名それぞれコロンが付いた形の配列が返ってきます(何もかも外部化したい病気)。

……動かない。動かないというか、つめ込まれた変数がおかしい。
途中にアイキャッチャー挟んで全ての変数を追ってもおかしいところがないのに、execute時点ではどうもデータが変わってしまっている。
時間は全て0000-00-00 00:00:00だし、吐出されるはずのSQLをphpMyAdminで叩いてみても異常は見られない。

結論

SQLStatement::bindParamの第二引数は 参 照 渡 し でした。
つまり、foreachループ内で$valの中身が変わるとそちらでSQLを作成してしまう。
私の場合末尾に入っていた文字列で全ての変数をバインド、DB側でエラーを起こして初期値が入ってしまう、ということでした。

リファレンス何回も見てたのになぜ気がつけなかったのか、こんなことで半日を潰しました。

解決策

SQLStatement::bindValueを使いましょう。
※ループ回さないできっちり変数名を指定するのが一番無難です。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2