Pull to refresh

PHP+SQL начинающим: Повышаем уровень программирования.

Reading time 5 min
Views 1.5K
Данная статья сугубо практическая и затрагивает единственный аспект – как повысить уровень програмирования в PHP при работе с SQL базой данных (в дальнейшем мы постараемся затронуть и другие аспекты программирования) Сразу же стоит оговориться, что есть высокий уровень программирования, дабы избежать лишних упреков. Под выским уровнем понимается достижение цели при минимальном и быстро получаемом коде (количества строк кода, символов в строке), даже если это идет в ущерб эффективности использования вычислительных ресурсов.

В настоящее время процессорное время, память и дисковое пространство стоит настолько дешево по сравнению с рабочим временем инженерного персонала, что им можно пренебрегать. Скорость разработки прикладной задачи гораздо важнее того, на сколько эффективно она работает. Если разработчик вместо 30 строк кода пишет только 10, то верятность ошибки снижется в три раза. Дальнейшее сопровождение и модификации более короткого кода тоже несомненно требует гораздо меньшего времени и человеческих ресурсов. Не забывайе, что мы не рассматриваем здесь системные решения, когда во главу угла ставится именно эффективность кода.

В данном статье мы создадим обертку для стандартной библиотеки PHP mysql. Не составит большого труда самостоятельно адаптировать ее для других баз данных. Это не будет попыткой создания ORM. У ORM совсем другие задачи, которые идут в разрез с нашей целью повысить уровень программирования и сократить код.

В качестве рабочего примера возьмем воображаемую таблицу данных пользователей следующей структуры:

CREATE TABLE users (
 id int auto_increment,
 category tinyint,
 name varchar(25),
 password char(32),
 email varchar(100)
);


Напомним, что обычным способом получения данных из таблицы будет примерно такой:

$result = mysql_query(«SELECT * FROM users»);
$users = array();
while ( $row=mysql_fetch_array($result) )
{
 $users[] = $row;
}


Что-то подсказывает, что такая конструкция из 5-6 строк повторяемая от раза к разу может (и должна!) быть заменена на более компактную. Понятно, что внутри цикла мы на самом деле можем производить какие-то более полезные действия, чем просто накопление массива. Здесь вступет в силу парадигма высокоуровневого програмирования, которая говорит, что не стоит смешивать в одно такое системное действие, как выборка результатов из ресурса базы данных с его прикладным использованием. Если вы даже могли бы и обойтись без массива $users, то теперь вам придется его получить и уже дальше работать с ним в режиме прикладной задачи.

Вводим новую функцию:

$users = sql_get_rows("SELECT * FROM users");


Ну вот и все. 5-6 строк кода, в которые еще надо вчитаться и понять, что они делают, заменены одной четкой и понятной строкой. Этот пример конечно чисто академический, на практике надо частенько как-то облагораживать получаемый результат. Например, мне хотелось бы получать напрямую доступ к строке с с заданным id. Рыскать по массиву в поисках нужного $users[‘id’] тоже не совсем правильно. Мы придусмотрели это:

$users = sql_get_rows("SELECT * FROM users", 'id');


Теперь в нашем массиве $users индексы идут не просто по порядку номеров, а соответствуют id данного пользователя. Мы пошли дальше и предусмотрели многомерные или лучше сказать древовидные массивы. Например вам нужно перечислить всех пользователей, но сгруппировав их по категориям. Пожалуйста:

$users = sql_get_rows("SELECT * FROM users", 'category', 'id');


Теперь рассмотрим частные случаи. Например вы знаете, что получите в результате всегда одну строку. Здесь мы предлагаем другую функцию:

$user = sql_get_row("SELECT * FROM users WHERE id=$id");


Почему другая функция. Ну во первых, если можно где-то ненароком повысить эффективность кода, то почему бы нет. Но это здесь не главное. Главное то, что человек, который будет читать этот код после вас, будет четко видеть, что результатом является одна строка. Кстати функция сама всегда добавляет в конце «LIMIT 1».
Ну и еще одна вырожденная функция:

$qty = sql_get_value("SELECT count(*) FROM users");


Как вы поняли, она возвращет единственную скалярную величину.

Для остальных запросов, которые не возвращают результата мы предусмотрели такую функцию:

$id = sql_query("INSERT INTO users ...");
$qty = sql_query("DELETE FROM users WHERE email='' ");


Заметьте, что на самом деле они тоже возвращают результат, и очень даже полезный. Для INSERT'а возвращется код auto_increment’а. Для DELETE и UPDATE – количество обработанных строк. Осталось только заполнить пробелы в месте многоточия в примере выше. Там, как вы, понимаете должны стоять данные, которыми заполнаются поля.

Вводим правило: данные должны поступать всегда в виде ассоциативного массива и никак иначе. Поверьте, это в всегда удобнее и гибче. Например вы прочитали строку из таблицы. Она приходит к вам в виде ассоциативного массива. Вы заменяте одельные значения, возможно удаляте какие-то поля (напр. ‘id’) и отдаете массив обратно на UPDATE или INSERT. Очень эффективно. Если увеличилось количество полей в таблице, то код практически нигде не надо подправлять.

Вводим еще одну вспомогательную функцию:

$set = sql_set($fields);
$id = sql_query("INSERT INTO users $set");


Не трудно догадаться, что функция sql_set() генерирует опцию SET со списком полей и данных: SET name='Vasya', password='56F54AC84',email='vasya@pupkin.com'

Таким образом, введя несколько высокоуровневых функций, мы повысили уровень программы. Длина тех кусков кода, которе отвечают за работу с базой сократилась примерно 5-7 раз, но самое главное повысилась читабельность кода и его семантическая чистота. Мы гарантируем, что в обычной прикладной задаче (то есть в 99% случаев) вам более не понадобиться обращаться к фунциям низкого уровня. Данных функций будет достаточно для решения практически любых прикладных задач.
В завершение приводим текст библиотеки (благо он совсем короткий). Любознательный читатель найдет там пару полезные вещей, которые не упомянуты в статье. Предупреждаем, что библиотека написана под error_reporting(E_ALL^E_NOTICE); Почему так – тема другой статьи о повышении уровня программирования. Но любой волен изменять в этой библиотеке все по своему вкусу.

//=========================================================
function sql_get_rows($query,$key_col=false,$key_col2=false)
{
  $array= array();
  $res= sql_query($query);
  if (mysql_num_rows($res)>0)
  {
   if ($key_col)
   {
    if ($key_col2) while ($item= mysql_fetch_assoc($res)) $array[$item[$key_col]][$item[$key_col2]]=$item;
    else while ($item= mysql_fetch_assoc($res)) $array[$item[$key_col]]=$item;
   }
   else while ($item= mysql_fetch_assoc($res)) $array[]=$item;
  }
  mysql_free_result($res);
  return $array;
}
//=========================================================
function sql_get_row($query)
{
  $res= sql_query($query.' LIMIT 1');
  $array= mysql_fetch_assoc($res);
  mysql_free_result($res);
  return $array;
}
//=========================================================
function sql_get_value($query)
{
  $res= sql_query($query);
  $array= mysql_fetch_row($res);
  mysql_free_result($res);
  return $array[0];
}
//=========================================================
function sql_query($query)
{
 mysql_query($query) or sql_query_die(mysql_error(),$query);
 if (substr($query,0,6)=='INSERT') $res= mysql_insert_id();
 if (!$res) $res= mysql_affected_rows();
 return $res;
}
//=========================================================
function sql_set($data, $skipslashes=false)
{
  sql_protect($data);
  $set_text='';
  foreach ($data as $col=>$val)
  {
   if (!$skipslashes) $val= addslashes($val);
   $set_text.= ",`$col`='$val'";
  }
  $set_text= substr($set_text,1); // remove very first comma
  return 'SET '.$set_text;
}
//=========================================================
function sql_query_die($error,$query)
{
  $backtrace=debug_backtrace();
  foreach ($backtrace as $step=>$trace) if (substr($trace['function'],0,4)!='sql_') break;
  $step--;
  die(«SQL: $error. Generated at: {$backtrace[$step]['file']}:{$backtrace[$step]['line']}\nFull query: '$query'»);
}
* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
+3
Comments 45
Comments Comments 45

Articles