bindParamとbindValueの違いについての覚書です。
bindValue : 値をパラメータにバインドする
プリペアドステートメントで使用する SQL 文の中で、対応する名前あるいは疑問符のプレースホルダに値をバインドします。
bindParam : 指定された変数名にパラメータをバインドする
準備された SQL ステートメント中で、 対応する名前もしくは疑問符プレースホルダにパラメータをバインドします。 PDOStatement::bindValue() と異なり、 変数は参照としてバインドされ、PDOStatement::execute()がコールされたときのみ評価されます。
PHPマニュアルの該当箇所には、このような説明があります。
ただ、これだけでは何のことかイマイチ分かりません。
この二つで分かりやすいのは、単純な動作のbindValueです。
基本的な動作は、こちらが素直です。どういうことかというと、bindValueメソッドが実行されると、その時点で、バインドされる値が確定します。下のコードだと、150とredという値が、bindValueされる時点で確定するということです。言い換えると、executeされる前に値が確定するのです。
$calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindValue(':calories', $calories, PDO::PARAM_INT); $sth->bindValue(':colour', $colour, PDO::PARAM_STR); $sth->execute();
これに対して、bindParamは、値が確定するタイミングが、bindValueよりも遅くなります。どういうことかというと、executeされるまでは、値を参照しているにすぎないのです。つまり、bindParamしても、値は確定していない。言い換えると、参照している変数の中身が変わると、別の値がバインドされる可能性があるということです。
これは、bindParamをループ内で使用すると不具合となって表れます。
Vili28-May-2010 12:01
//これは動かない。なぜなら、$valの値が上書きされてしまうから。 This will fail ($val by value, because bindParam needs &$variable): <?php foreach ($params as $key => $val) { $sth->bindParam($key, $val); } ?>
//これは上手く動く。なぜなら、参照を渡しているから。 This works ($val by reference): <?php foreach ($params as $key => &$val) { $sth->bindParam($key, $val); } ?>
上のように、&をつけて参照にすると上手く動きますが、このような場合には、bindValueして、その時点で値を確定してやると、同様に上手く動くようになります。
PHPの参考書などでは、理由なくbindParamの方が多用されていますが、単純なバインドをするなら、bindValueで足りると思われます。
ループ内でbindParamをして不具合が生じているなら、以上の点を確認してみると上手くいくはずです。