【PDO】bindParamとbindValueの違い【PHP】

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をして不具合が生じているなら、以上の点を確認してみると上手くいくはずです。

カテゴリー: PHP パーマリンク

コメントを残す

メールアドレスが公開されることはありません。