Пример исправления алгоритма формирования оператора where для sql-запроса


Исходный код

if ($category) {$zapros="where category='$category'"; $f[1]=1;}

if ($group) {
  if ($f[1]==1) {$zapros.=" and idu='$row[0]'";}
  else {$zapros="where idu='$row[0]'";}
  $f[2]=1;
}
if ($type) {
  if (($f[1]==1)||($f[2]==1)) {$zapros.=" and type='$type'";}
  else {$zapros="where type='$type'";}
  $f[3]=1;
}

if ($format) {
  if (($f[1]==1)||($f[2]==1)||($f[3]==1)) {$zapros.=" and format='$format'";}
  else {$zapros="where format='$format'";}
  $f[4]=1;
}
if ($curlang) {
  if (($f[1]==1)||($f[2]==1)||($f[3]==1)||($f[4]==1)) {$zapros.=" and (lang='$curlang' or lang='all')";}
  else {$zapros="where (lang='$curlang' or lang='all')";}
  $f[5]=1;
}

Что не так в исходном коде

Здесь сразу несколько проблем различной степени тяжести.

  1. Однородная обработка данных выполняется без массивов и циклов, что приводит к ненужным переменным и проверкам. Конкретно здесь цикл здесь ни к чему, так как входные данные раскиданы по разным переменным, а вот массив для выходных данных очень даже пригодится.
  2. Смешаны ответственности по формированию каждого отдельного условия, всего набора условий, а также оператора where.
  3. Дублируется реализация по каждому отдельному условию: $zapros.=" and idu='$row[0]'" и $zapros="where idu='$row[0]'".
  4. Отсутствует защита от SQL инъекций.
  5. Имеет место неявная связь между $group и $row[0], которая может испортить жизнь при будущих доработках алгоритма.
  6. Неудачно выбрано название переменной $zapros: во-первых, по-русски, во-вторых, в ней формируется не сам sql-запрос, а только where clause от него (по крайней мере, в данном участке кода).

Как улучшить исходный код

function makeConditionField($field_name, $field_value, $op = '=') {
  return $field_value ? "$field_name $op '$field_value'" : null;
}

function makeConditionLang($lang) {
  return $lang ? "(lang='$lang' or lang='all')" : null;
}

function joinConditionsAnd($conditions) {
  return implode(' and ', array_filter($conditions));
}
$conditions[] = makeConditionField('category', $category);
$conditions[] = makeConditionField('idu', $idu);
$conditions[] = makeConditionField('type', $type);
$conditions[] = makeConditionField('format', $format);
$conditions[] = makeConditionLang($lang);
$conditions_str = joinConditionsAnd($conditions);
$where = empty($conditions_str) ? '' : "where $conditions_str";

Теория