Web Developer's Struggle Memories

日々の業務から思ったこと、学んだことを書き連ねていきます。

PHPで配列の要素数と同じ数のプレースホルダを生成する方法

PHPからSQLを作る

ことの発端は、PHPからDBにアクセスしデータを抽出するためにSQLを書くのだが、取得している配列の要素を全て条件に加えたい。

素数によってプレースホルダの数も変化するので、 動的にプレースホルダを生成する必要がある。その生成方法の話。

やりたいこと

やりたいことは['aa', 'bb', 'cc']こんな配列があったときに、

SELECT * FROM hoge_table WHERE hoge_id IN ('aa', 'bb', 'cc');

PHPでこんなSQLを作りたい。
もちろんこのままだとSQLインジェクションを招くので、プレースホルダで置き換えて、

<?php

'SELECT * FROM hoge_table WHERE hoge_id IN (?, ?, ?)', array('aa', 'bb', 'cc')

?>

こうしたい。どうするか?

方法1(駄目な方法)

頭使わずに直接的に生成した方法。
foreachで繰り返し処理させており、その上if文で判定もしていて処理の回数が多い。

<?php
$arrVal = array('aa', 'bb', 'cc');

$where = 'hoge_id in (';
$arrIds = explode(',', $arrVal);
foreach ($arrIds as $key => $val) {
    // 途中の場合','でつなぐ
    if ($key + 1 != count($arrIds)) {
        $where .= '?, ';
    // 最後の場合')'で閉じる
    } else {
        $where .= '?)';
    }
}

var_dump($where);    // hoge_id IN (?, ?, ?)
?>

 

方法2(良い方法)

改良した方法。implodearray_fillという2つの関数を使うと上記の処理が1行で書ける。

<?php
$arrVal = array('aa', 'bb', 'cc');

$where = 'hoge_id IN (' . implode(',', array_fill(0, count($arrVal), '?')) . ')';

var_dump($where);    //  hoge_id IN (?, ?, ?)
?>

ちょっと解説する。
array_fill(0, count($arrVal), '?')の部分で、['aa', 'bb', 'cc']から

<?php
array(3) {
    [0]=> string(1) "?"
    [1]=> string(1) "?"
    [2]=> string(1) "?"
}
?>

という配列を生成し、この配列をimplode関数を用いてカンマ区切りにする。
(特に説明は要らなかったか)  

まとめ

PHPには組み込み関数が豊富にある。何かしたければまず探してみる。
特に配列に関する関数が多いので、絶対やるべき。
以前会社の先輩から、「配列を制するものはPHPを制す」とのお言葉をいただきました。
(某名作漫画のパクリではないよ、きっと…)

PHPはどこまでも配列との戦いなんだな。