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

Если подойти к этому вопросу "в лоб", то код станет очень неудобен как для понимания, так и для использования: код станет переполнен различными функциями соединения с БД, отправки запросов, преобразования результатов запросов в массивы PHP, подсчета строк, которые затронул запрос, а также многие и многие другие.

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

Этим способом будет являться написание класса, реализующего интерфейс между СУБД и PHP-скриптами. Для начала стоит определиться с ассортиментом функций, которые будет призван выполнять наш класс:

  • установка соединения, а также проверка успешности выполнения этого действия;
  • отправка запросов, как заданных извне так и, возможно, из какого-либо ассортимента заранее написанных запросов;
  • обработка результатов запросов, не ограничивающаяся одним SELECT, должны быть предоставлены методы обработки результатов любых видов запросов (или хотябы большинства).

Вполне очевидным является тот факт, что методы этого класса будут использоваться практически повсеместно в большинстве проектов. Вследствии чего становится нецелесообразным создание объекта нашего класса и передача его по всем функциям и методам всех скриптов, в таких случае намного предпочтительнее делать владельцем методов и переменных сам класс, а не экземпляр класса, с помощью ключевого слова static. Это позволит пользоваться услугами нашего класса из любого места кода. Приступим-с собственно к кодингу, начать стоит с заготовки пустого класса:

<?php
class SQL
{
}
?>

В зависимости от предпочитаемой Вами СУБД набор конкретных функций, используемых в реализации нашего класса, будет вариироваться. В большинстве случаев предпочитаю пользоваться PostgreSQL, на это причин у меня несколько, но это тема для отдельного разговора. Благодаря этому факту приводимый в качестве примера код будет использовать функции для работы именно с этой СУБД. Для поклонников же других этот систем вопрос в подавляющем большинстве случаев заключается лишь в замене этих функций на аналогичные из других модулей PHP, например для популярной и широкораспространенной MySQL достаточно будет всеголишь пройтись автозаменой pg_ => mysql_ и слегка подредактировать параметры некоторых функций.

Перейдем к реализации установления соединения с СУБД, не стоит ожидать увидеть здесь ничего необычного:

<?php
static function connect()  // установка соединения
{
  self::$connection=pg_pconnect("host=localhost dbname=pgsql user=pgsql password=MyPassword");
  // не забываем менять указанные данные для авторизации на правильные
  if(!isset(self::$connection))
  {
    echo "Сайт не работает по техническим причинам.
Просим прощения за доставленные неудобства.";
    exit;   // ни в коем случае не выводим более информативных сообщений об ошибке, чем это
  }
}
?>

А вот с отправкой и обработкой результатов запросов ситуация далеко не так однозначна. Помимо простой передачи самого текста запроса в СУБД, необходимо правильно определить тип запроса и в соответствии с этим обработать результат. Можно конечно попытаться сделать это автоматически на основе вытаскивания первого слова из текста запроса, но мне всетаки кажется более предпочтительным определение "вручную" желаемого вида представление результата. Выполнение произвольных запросов может выглядеть, например, следующим образом:

<?php
static function query($str,$bool=false) // произвольный запрос
{
  //echo $str."
"; // очень удобно на стадии разработки в процессе поиска ошибок
  $result=@pg_query(self::$connection,$str); // @ - для сокрытия теоретически возможных ошибок
  // or die('Query failed: '.pg_last_error());
  // не забываем убирать в комментарий в финальном варианте проекта
  // или совсем удалять
  if($result)  // Если получен результат, отличный от false
  {
    if($bool)  // Если выбран результат в виде boolean
    {
      return true;
    }
    else  // Если выбран результат в виде массива
    {
      $n=pg_num_rows($result);  // для создания универсального формата массива
      if($n==1)return pg_fetch_array($result,0,PGSQL_ASSOC);
      else  // даже когда результат содержит только одну строку
      {
        $j=pg_num_rows($result);
        $list=array();
        for($i=0;$i<$j;$i++)
        $list[]=pg_fetch_array($result,$i,PGSQL_ASSOC);
        return $list;
      }
    }
  }else return false;
}
?>

Помимо базовой отправки запросов, в некоторых случаях имеет смысл написать несколько методов, отправляющих частоиспользуемые запросы, что в некоторых случаях позволяет сократить объем и уменьшить нагроможденность кода. Хоть я и предпочитаю не пользоваться такими вещами, но привести пример такого рода метода все же стоит:

<?php
static function selectAll($table)
{ // пример метода отправки чаcтоиспользуемых запросов
  return self::query("select * from ".$table.";");
}
?>

Если чувствуете необходимость в подобных функциях, можно написать огромное количество, все ограничивается лишь Вашим воображением и знаниями SQL.

Что ж, осталось лишь собрать весь код в единый листинг:

<?php
class SQL
{
  private static $connection; // соединение с СУБД
  static function connect()  // установка соединения
  {
    self::$connection=pg_pconnect("host=localhost dbname=pgsql user=pgsql password=MyPassword");
    // не забываем менять указанные данные для авторизации на правильные
    if(!isset(self::$connection))
    {
      echo "Сайт не работает по техническим причинам.<br />Просим прощения за доставленные неудобства.";
      exit; // ни в коем случае не выводим более информативных сообщений об ошибке, чем это
    }
  }
  static function query($str,$bool=false) // произвольный запрос
  {
    //echo $str."<br>"; // очень удобно на стадии разработки в процессе поиска ошибок
    $result=@pg_query(self::$connection,$str); // @ - для сокрытия теоретически возможных ошибок
    // or die('Query failed: '.pg_last_error());
    // не забываем убирать в комментарий в финальном варианте проекта
    // или совсем удалять
    if($result)  // Если получен результат, отличный от false
    {
      if($bool)  // Если выбран результат в виде boolean
      {
        return true;
      }
      else  // Если выбран результат в виде массива
      {
        $n=pg_num_rows($result);  // для создания универсального формата массива
        if($n==1)return pg_fetch_array($result,0,PGSQL_ASSOC);
        else  // даже когда результат содержит только одну строку
        {
          $j=pg_num_rows($result);
          $list=array();
          for($i=0;$i<$j;$i++)
          $list[]=pg_fetch_array($result,$i,PGSQL_ASSOC);
          return $list;
        }
      }
    }else return false;

  }
  static function selectAll($table)
  { // пример метода отправки чаcтоиспользуемых запросов
    return self::query("select * from ".$table.";");
  }
}
?>

```

Вот так вот оно и выглядит в простейшем варианте, дорабатывать под собственные нужды код можно до бесконечности естественно, но в большинстве случаев даже такой реализации вполне должно хватать.

Эта статья является частью серии статей "Джентельменский набор PHP программиста", если Вам понравилась эта статья то очень вероятно, что Вам придутся по душе и остальные статьи.

Не забываем подписываться на RSS блога!

16 января 2008 |  Иван Блинков  |  PHP