PHP/mysqliのSQLステートメントのパラメータの数が可変する時のbind_paramのやり方

PHPからMySQLを利用する時は、mysqliを使うことが推奨されています。
mysqliはSQLステートメントを設定した後、パラメータマーカに対して値をバインドしてSQLを実行する流れになります。

$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);

このときのバインドは当然ながら、bind_paramに渡す引数の数とパラメータマーカの数が一致していないとなりません。上記で言うと、パラメータマーカ「?」が4つあるので、bind_paramには型指定の文字列と、そこにバインドする値($code, $language, $official, $percent)を順番に引数に入れるわけです。

パラメータマーカの数が変わる場合

基本にはあまりSQLにバインドする変数の数が変わることは無いと思いますが、例えば検索でLIKEやREGEXPを実行する場合に、複数単語の入力で絞り込み機能などを実装しようとすると、検索語の数が特定出来ないことがあります。

//単語1個で検索
$stmt = $mysqli->prepare("SELECT * FROM `table_name` WHERE `data_name` REGEXP ?");
$stmt->bind_param('s', $keyword1);

//単語2個でAND検索
$stmt = $mysqli->prepare("SELECT * FROM `table_name` WHERE `data_name` REGEXP ? and `data_name` REGEXP ?");
$stmt->bind_param('ss', $keyword1, $keyword2);

//単語3個でAND検索
$stmt = $mysqli->prepare("SELECT * FROM `table_name` WHERE `data_name` REGEXP ? and `data_name` REGEXP ? and `data_name` REGEXP ?");
$stmt->bind_param('sss', $keyword1, $keyword2, $keyword3);

検索語の数に合わせてSQL文を調整することは簡単ですが、bind_paramの引数の数を変えるのはちょっと難しいです。evalでも出来るかもしれませんが、あまり使いたくないですね。

ここは、call_user_func_arrayを使ってbind_paramを実行すると上手くいくようです。
call_user_func_arrayは、第一引数に関数、第二引数にパラメータを配列で指定すると、配列分の引数を関数に渡して実行してくれます。

//$dataの配列は要素数が可変:以下例では3つあるとする
$data = array($keyword1,$keyword2,$keyword3);

//SQL文を作る:キーワード分の`data_name` REGEXP ?'をandで連結
$sql = "SELECT * FROM `table_name` WHERE ".
implode( ' and ', array_fill(0, count($data), '`data_name` REGEXP ?') );

$stmt = $mysqli->prepare($sql);

//パラメータ用配列を作る
//型指定:この例では$stmtParams[0]に'sss'が入る
$stmtParams = array( str_repeat( 's', count($data) ) );
//$stmtParams[1]~にそれぞれデータを参照渡しする
//※ここは参照渡しでないとNG
foreach ($data as $k=>$v){
  $stmtParams[] = &$data[$k];
}

//call_user_func_array経由でbind_paramに渡す
call_user_func_array(array($stmt, 'bind_param'), $stmtParams);

このようにすると、$dataの要素数がいくつあってもバインド出来ます。
あとは普通にexcuteするだけです。

コメント

  1. […] PHP/mysqliのSQLステートメントのパラメータの数が可変する時のbind_paramのやり方 […]

タイトルとURLをコピーしました