[PHP] mysqliのbind paramに可変する引数を渡す
プリペアドステートメントの「?」の数を動的に変化させる方法。
例えば、画面で検索条件が複数指定できて、「検索」的なボタンを押すたびに、 SQL の WHERE
句に指定する条件を変えたい場合。または、テーブルの各行にチェックボックスあって、チェックされた数だけ、 WHERE
句の条件が増える時に使う。
WHERE orderid IN (?,?) を可変にする
SELECT * FROM table WHERE id IN (?,?,?,....)
こんな SQL があって、 IN
のあとの '?'
を可変にしたい場合
「… による引数のアンパック」を使う
$stmt->bind_param($paramType, ...$stmtArray);
...
つければ、配列を bind_param
の引数に指定できるPHP 5.6 以上から使える
PHP マニュアル 「… による引数のアンパック」
// チェックボックスの値が配列で送られてくるとか
$ids = filter_input(INPUT_POST, 'id', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$sql = 'SELECT * FROM table WHERE id IN ('.implode(',', array_fill(0, count($ids), '?')).')';
$stmt = $mysqli->prepare($sql);
// idが文字列だったら's'、数値だったら'i'
$stmt->bind_param(str_repeat('s', count($ids)), ...$ids);
$stmt->execute();
$res = $stmt->get_result();
クエリ( $sql
のとこ) にはバインドさせたいパラメータの数だけ '?'
を出力しなければならないので、 array_fill(初めの要素のインデックス番号, 要素の数, 値)
で '?'
の値をもつ配列を作り、 implode(連結文字 , 連結したい配列)
で、カンマ区切りの '?'
連結文字列を出力する。
bind_param
の第一引数は、バインド変数の数だけ型 ( s
= string, i
= integer, d
= double, b
= blob) を指定するので、 str_repeat(出力する文字列, 反復回数)
で必要な個数分出力する。
call_user_func_array
を使う
PHP 5.6 以下使ってる場合は、上記のアンパックは使えないのでこっち
call_user_func_arrayとは
(引数を持つ)関数の引数に配列を渡し、その関数を実行させることができる
PHP マニュアル call_user_func_array
// チェックボックスの値が配列で送られてくるとか
$ids = filter_input(INPUT_POST, 'id', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$sql = 'SELECT * FROM table WHERE id IN ('.implode(',', array_fill(0, count($ids), '?')).')';
//IN句の組み立て
$sqlParams = [];
$sqlParams[0] = "";
foreach($ids as $key => $val) {
$sqlParams[0] .= "s";
$sqlParams[] = $val;
}
// bind_paramに渡す引数を参照渡しにする
$params = [];
foreach ($sqlParams as $key => $value) {
$params[$key] = &$sqlParams[$key];
}
// プリペアドステートメント
if ($stmt = $mysqli->prepare($sql)) {
// 変数のバインド
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
bind_param
に渡す引数は参照渡しでなければならない
&
をつけると、参照渡しになる
WHERE
句の検索条件が可変する
WHERE name=? and id=?
とか WHERE id=?
とか、 WHERE
句の条件が可変で組み立てが必要な時
「… による引数のアンパック」版
// POSTで送られてきた
$chk = filter_input(INPUT_POST, 'chk', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$name = filter_input(INPUT_POST, 'name');
$sql='select * from tableA';
$sqlWhere = [];
// WHERE句の組み立て
if (!empty($chk) ) {
$sqlWhere[] = 'id IN ('.implode(',', array_fill(0, count($chk), '?')).')';
}
if (!empty($name)) {
$sqlWhere[] = "name = ?";
$chk[] = $name;
}
if (count($sqlWhere) > 0) {
$sql .= ' WHERE ' . implode(" and ", $sqlWhere);
}
$stmt = $mysqli->prepare($sql);
$stmt->bind_param(str_repeat( 's', count($chk)), ...$chk);
$stmt->execute();
$res = $stmt->get_result();
count($chk)
するため、 $name
を $chk[]
に追加している。
以上