【PHPコード簡略化計画③】PHPからSQL文を作成するときのコツ

PHP
composita / Pixabay

PHPというか、コードでSQL文をかいて、それを投げる際のコツみたいなものを教えて頂いたのでそれについてまとめます。

おそらく言語に関係なく、SQLを書く時に少しは役に立つので書く際にこんなこと言ってたなーと思い出していただければ幸いです。

今回の状況

・よくある検索ページの作成
・利用するのは不特定多数の人
・検索の条件で選べる項目はよく増える

コーディング

あんまり良くない例

HTML側

<form action="phpのpath or URL" method="POST">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge">
  mogemoge : <input type="checkbox" name="inputData[]" value="mogemoge">

  <button type="submit">送信</button>
</form>
PHP側の処理
// 空のWhereを作成
$where = ""

// postで送信されてきた値をinputDatasとして定義
$inputDatas = $_POST["inputDatas"]

// 入力されたデータを配列として扱う
foreach ($inputDatas as $inputData) {
  if ($inputData == "hogehoge") {
    // whereが空の時は先頭だと判断してWHEREを、空でない時はANDを先頭に付けてくっつける
    $where = $where = "" ? "WHERE hogehoge = 1" : "AND hogehoge = 0 ";
  }
  if ($inputData == "mogemoge") {
    $where = $where = "" ? "WHERE mogemoge = 1" : "AND mogemoge = 0 ";
  }
}

$sql = "SELECT a,b,c FROM hoge_table " . $where;

良くない点

・数が増えた際に無駄に通るif文が大量に発生する
・検索するための条件を追加するたびにforeachが大きくなる
・WHEREをつけるかの判断は複数回する必要が無い

大きく分けるとこんな所ですかね。

では、上記の良くない点を改善してみたコードを見てみましょう。

条件が追加された時にも対応できる例

HTML

HTML側

<form action="phpのpath or URL" method="POST">
  hogehoge : <input type="checkbox" name="inputData[hogehoge]" value="1">
  mogemoge : <input type="checkbox" name="inputData[mogemoge]" value="1">

  <button type="submit">送信</button>
</form>

PHP

PHP側の処理
// wheresを配列で定義
$wheres = array()

// postで送信されてきた値をinputDatasとして定義
$inputDatas = $_POST["inputDatas"]

// 取得する値をphp側で定義
// html側を書き換えられて、テーブルにあるカラムを指定されたらSQLインジェクションを起こされる可能性があるため
$conditions = array("hogehoge","mogemoge");

// 入力されたデータを配列として扱い
foreach ($conditions as $condition) {
  // 想定外の値を入れられないように、プリペアドステートメントを使う
  $wheres[] = $condition." = ? " ;
  $params[] = $inputDatas[$condition];
}

// 条件文が存在した場合には$wheres配列にANDを間に挟んで展開
if (count($wheres) > 0) {
  $where = "WHERE ".implode(" AND ", $wheres);
}

$sql = "SELECT a,b,c FROM hoge_table ".$where;

// プリペアドステートメントに値を入れる
$stmt = $pdo->prepare($sql);
$stmt->execute($params);

// SQL実行!
$res = $stmt->fetchAll();

この形にすることでもし条件の数が増えていったとしても修正はHTML側に1行追加とPHP側の$conditions配列にデータを追加するだけでよく、しかも見た目もスッキリしていますね。

試しに入力される検索条件が10個だった場合で比較してみましょう。

あんまりよくない例 10連ver

HTML

<form action="phpのpath or URL" method="POST">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge1">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge2">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge3">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge4">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge5">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge6">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge7">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge8">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge9">
  hogehoge : <input type="checkbox" name="inputData[]" value="hogehoge10">
  <button type="submit">送信</button>
</form>

PHP

PHP側の処理
$where = ""
 
// postで送信されてきた値をinputDatasとして定義
$inputDatas = $_POST["inputDatas"]
 
// 入力されたデータを配列として扱う
foreach ($inputDatas as $inputData) {
  if ($inputData == "hogehoge1") {
    $where = $where = "" ? "WHERE hogehoge1 = 1" : "AND hogehoge1 = 0 ";
  }
  if ($inputData == "hogehoge2") {
    $where = $where = "" ? "WHERE hogehoge2 = 1" : "AND hogehoge2 = 0 ";
  }
  if ($inputData == "hogehoge3") {
    $where = $where = "" ? "WHERE hogehoge3 = 1" : "AND hogehoge3 = 0 ";
  }
  if ($inputData == "hogehoge4") {
    $where = $where = "" ? "WHERE hogehoge4 = 1" : "AND hogehoge4 = 0 ";
  }
  if ($inputData == "hogehoge4") {
    $where = $where = "" ? "WHERE hogehoge4 = 1" : "AND hogehoge4 = 0 ";
  }
  if ($inputData == "hogehoge5") {
    $where = $where = "" ? "WHERE hogehoge5 = 1" : "AND hogehoge5 = 0 ";
  }
  if ($inputData == "hogehoge6") {
    $where = $where = "" ? "WHERE hogehoge6 = 1" : "AND hogehoge6 = 0 ";
  }
  if ($inputData == "hogehoge7") {
    $where = $where = "" ? "WHERE hogehoge7 = 1" : "AND hogehoge7 = 0 ";
  }
  if ($inputData == "hogehoge8") {
    $where = $where = "" ? "WHERE hogehoge8 = 1" : "AND hogehoge8 = 0 ";
  }
  if ($inputData == "hogehoge9") {
    $where = $where = "" ? "WHERE hogehoge9 = 1" : "AND hogehoge9 = 0 ";
  }
  if ($inputData == "hogehoge10") {
    $where = $where = "" ? "WHERE hogehoge10 = 1" : "AND hogehoge10 = 0 ";
  }
}
 
$sql = "SELECT a,b,c FROM hoge_table " . $where;

条件が追加された時にも対応できる例 10連ver

HTML 

<!-- SQLに使いたい条件文と値を投げる -->
<form action="phpのpath or URL" method="POST">
  hogehoge : <input type="checkbox" name="inputData[hogehoge1]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge2]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge3]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge4]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge5]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge6]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge7]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge8]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge9]" value="1">
  hogehoge : <input type="checkbox" name="inputData[hogehoge10]" value="1">
  <button type="submit">送信</button>
</form>

PHP

PHP側の処理
// wheresを配列で定義
$wheres = array()
 
// postで送信されてきた値をinputDatasとして定義
$inputDatas = $_POST["inputDatas"]
 
// 取得する値をphp側で定義
$conditions = array(
  "hogehoge1",
  "hogehoge2",
  "hogehoge3",
  "hogehoge4",
  "hogehoge5",
  "hogehoge6",
  "hogehoge7",
  "hogehoge8",
  "hogehoge9",
  "hogehoge10",
 );
 
foreach ($conditions as $condition) {
  $wheres[] = $condition." = ? " ;
  $params[] = $inputDatas[$condition];
}

$where = count($wheres) > 0 ? "WHERE ".implode(" AND ", $wheres) : ""; 
$sql = "SELECT a,b,c FROM hoge_table ".$where;
 
// プリペアドステートメントに値を入れる
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
 
// SQL実行!
$res = $stmt->fetchAll();

10個にするとよくわかりますが、2つ目の方がだいぶスッキリしていますね。

まとめ

プログラミングを書く時は、未来の人たちのために修正が簡単で読みやすいコードを書くことを意識するように教えていただきました。
ただ修正が簡単で読みやすいようにかけというのは漠然としていて難しい、、、。

なので、意識するべきなのは

・条件がめっちゃ増えた時に対応できるか
・同じことを繰り返している所が無いか

この2つを書き終わった後に考えるということだと思います。

私自身もまだまだ冗長なコードばっかり書いてしまっているので、意識して頑張って行きます!!

では今日はこれまで。。。

コメント

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