За последние 24 часа нас посетили 18064 программиста и 1651 робот. Сейчас ищут 1679 программистов ...

Класс для работы с PDO

Тема в разделе "Решения, алгоритмы", создана пользователем sylex, 8 июн 2011.

  1. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    Мини-обертка такая получилась, требую критики :)

    PHP:
    1. <?php
    2.  
    3. /**
    4.  * Класс для работы с БД (PDO)
    5.  *
    6.  * @package     AcFrame
    7.  * @author      Sylex
    8.  * @copyright   2011, AcFrame
    9.  * @version     1.0 (2011/06/08)
    10.  */
    11.  
    12. class db
    13. {
    14.     /**
    15.      * Экземпляр объекта
    16.      *
    17.      * @var object
    18.      */
    19.     private static $_instance;
    20.    
    21.     /**
    22.      * Текущая БД (в конфиге)
    23.      *
    24.      * @var string
    25.      */
    26.     private static $_name;
    27.    
    28.     /**
    29.      * Режим отладки
    30.      *
    31.      * @var int
    32.      */
    33.     private static $_debug = 0;
    34.    
    35.     /**
    36.      * Режим записи ошибок в лог
    37.      *
    38.      * @var int
    39.      */
    40.     private static $_log_error = 0;
    41.    
    42.     /**
    43.      * Время выполнения запроса в секундах - для записи запросов в лог (если 0 - отключено)
    44.      *
    45.      * @var int
    46.      */
    47.     private static $_log_sql = 0;
    48.    
    49.     /**
    50.      * Вывод времени выполнения запросов
    51.      *
    52.      * @var int
    53.      */
    54.     private static $_print_time = 0;
    55.    
    56.     /**
    57.      * Счетчик количества запросов
    58.      *
    59.      * @var int
    60.      */
    61.     private static $_nq = 0;
    62.    
    63.     /**
    64.      * Текущее подготовленное выражение
    65.      *
    66.      * @var object
    67.      */
    68.     private static $_statement = null;
    69.  
    70.     // Запрещаем создавать объект
    71.     private function __construct() {}
    72.  
    73.     // Запрещаем клонировать объект
    74.     private function __clone() {}
    75.    
    76.     /*
    77.      * Вызов всех статических методов для PDO (PHP ver. >= 5.3)
    78.      *
    79.      * @param $method - метод
    80.      * @param $arguments - аргументы
    81.      * @return mixed
    82.      */
    83.     final public static function __callStatic($method, $arguments)
    84.     {
    85.         $_instance = self::init();
    86.         return call_user_func_array(array($_instance, $method), $arguments);
    87.     }
    88.  
    89.     /*
    90.      * Возвращает текущий экзмепляр объекта PDO или создает новое соединение
    91.      *
    92.      * @param string $name - имя конфига
    93.      * @return object
    94.      */
    95.     public static function init($name = '')
    96.     {
    97.         // по умолчанию - default
    98.         if (empty($name)) $name = !empty(self::$_name) ? self::$_name : 'default';
    99.         // если нет соединения, или новое
    100.         if (!self::$_instance || self::$_name != $name) {
    101.             // проверка, установленно ли расширение
    102.             if (!class_exists('PDO')) {
    103.                 self::error('Extension PDO not installed');
    104.             }
    105.             // загрузка конфига БД
    106.             $config = Config::read('database');
    107.             $db_config = $config[$name];
    108.             self::$_debug = (int) $db_config['debug'];
    109.             self::$_log_error = (int) $db_config['log_error'];
    110.             self::$_log_sql = isset($db_config['log_sql']) ? floatval($db_config['log_sql']) : 0;
    111.             $params = array(
    112.                 PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES '{$db_config['char']}'",
    113.                 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    114.             );
    115.             // создание нового соединения
    116.             try {
    117.                 self::$_instance = new PDO("{$db_config['driver']}:host={$db_config['host']};dbname={$db_config['name']}", $db_config['user'], $db_config['pass'], $params);
    118.             } catch (PDOException $e) { // не срабатывает
    119.                 self::error('Connection failed: ' . $e->getMessage());
    120.             }
    121.             self::$_name = $name;
    122.         }
    123.         return self::$_instance;
    124.     }
    125.    
    126.     /*
    127.      * Выполняет запрос
    128.      *
    129.      * @param string/array $sql - запрос
    130.      * @return bool
    131.      */
    132.     public static function query($sql)
    133.     {
    134.         $state = false;
    135.         if (is_array($sql)) {
    136.             // если передан как массив - вытаскиваем данные
    137.             $args = func_get_args();
    138.             $args = isset($args[0]) ? $args[0] : array('');
    139.             $sql = strval(array_shift($args));
    140.         }
    141.         if (empty($sql)) return false;
    142.         if (self::$_print_time == 1 || self::$_log_sql > 0) {
    143.             benchmark::startTimer('db_query');
    144.         }
    145.         try {
    146.             self::$_statement = self::init()->prepare($sql);
    147.         } catch (PDOException $e) {
    148.             $es = array();
    149.             foreach($e->getTrace() as $v) {
    150.                 $es[] = $v['file'] . ' on line ' . $v['line'];
    151.             }
    152.             $es = implode("\n", $es);
    153.             self::error('['.$e->errorInfo[1].'] ' . $e->errorInfo[2]. "\n\nQuery: <b>" . $sql . "</b>\n\n" . $es . "\n", $e->errorInfo[0]);
    154.         }
    155.         if (is_object(self::$_statement)) {
    156.             if (!isset($args)) {
    157.                 $args = func_get_args();
    158.                 array_shift($args);
    159.             }
    160.             if (func_num_args() > 1) { if (is_array($args[0])) { $args = $args[0]; } }
    161.             try {
    162.                 $state = self::$_statement->execute($args);
    163.                 self::$_nq++;
    164.             } catch(Exception $e) {
    165.                 $es = array();
    166.                 foreach($e->getTrace() as $v) {
    167.                     $es[] = $v['file'] . ' on line ' . $v['line'];
    168.                 }
    169.                 $es = implode("\n", $es);
    170.                 self::error('['.$e->errorInfo[1].'] ' . $e->errorInfo[2]. "\n\nQuery: <b>" . $sql . "</b>\n\n" . $es . "\n", $e->errorInfo[0]);
    171.             }
    172.             // логирование по времени
    173.             if (self::$_print_time == 1 || self::$_log_sql > 0) {
    174.                 $time = benchmark::getTimer('db_query');
    175.                 if (self::$_print_time == 1) {
    176.                     // на экран
    177.                     echo $time, '<br />', $sql, '<br /><br />';
    178.                 } elseif($time >= self::$_log_sql) {
    179.                     // в файл
    180.                     @file_put_contents(LOG . date('Y-m-d') . '_db_query.log', date('Y-m-d H:i:s') . ' ' . self::$_name . ' *** ' . $time . ' - ' . $sql . "\n\n", FILE_APPEND);
    181.                 }
    182.             }
    183.             if ($state === false) {
    184.                 $e = self::$_statement->errorInfo();
    185.                 self::error('['.$e[1].']',$e[2]. "\nQuery: " . $sql, $e[0]);
    186.             }
    187.         }
    188.  
    189.         return $state;
    190.     }
    191.  
    192.     /**
    193.      * Возвращает одно значение
    194.      *
    195.      * @param string $sql - запрос
    196.      * @return mixed
    197.      */
    198.     public static function getOne($sql) {
    199.         self::query(func_get_args());
    200.         return is_object(self::$_statement) ? self::$_statement->fetchColumn() : false;
    201.     }
    202.  
    203.     /**
    204.      * Возвращает строку
    205.      *
    206.      * @param string $sql - запрос
    207.      * @return mixed
    208.      */
    209.     public static function getRow($sql) {
    210.         self::query(func_get_args());
    211.         return is_object(self::$_statement) ? self::$_statement->fetch(PDO::FETCH_OBJ) : false;
    212.     }
    213.    
    214.     /*
    215.      * Возвращает ряд строк
    216.      *
    217.      * @param string/array $sql - запрос
    218.      * @return mixed
    219.      */
    220.     public static function getAll($sql)
    221.     {
    222.         self::query(func_get_args());
    223.         return is_object(self::$_statement) ? self::$_statement->fetchAll(PDO::FETCH_OBJ) : false;
    224.     }
    225.    
    226.     /*
    227.      * Обработка исключений
    228.      *
    229.      * @param string $message - сообщение
    230.      * @param int $code - код ошибки
    231.      */
    232.     private static function error($message, $code = 0)
    233.     {
    234.         if (self::$_log_error == 1) {
    235.             @file_put_contents(LOG . date('Y-m-d') . '_db_error.log', date('Y-m-d H:i:s') . ' *** ' . $code . ' - ' . $message. "\n\n", FILE_APPEND);
    236.         }
    237.         if (self::$_debug == 0) {
    238.             throw new Error('error in ' . __CLASS__, -1);
    239.         } elseif(self::$_debug == 1) {
    240.             throw new Error($message, $code);
    241.         }
    242.     }
    243.    
    244.     /**
    245.      * Установка кодировки
    246.      *
    247.      * @param string $char - кодировка
    248.      */
    249.     public static function setNames($char)
    250.     {
    251.         db::init();
    252.         self::query("SET NAMES ?", $char);
    253.     }
    254.    
    255.     /**
    256.      * Установка режима отладки
    257.      *
    258.      * @param int $mode - режим
    259.      */
    260.     public static function setDebug($mode)
    261.     {
    262.         db::init();
    263.         self::$_debug = (int) $mode;
    264.     }
    265.    
    266.     /**
    267.      * Установка режима вывода времени выполнения запросов на экран
    268.      *
    269.      * @param int $mode - режим
    270.      */
    271.     public static function setPrintTime($mode)
    272.     {
    273.         self::$_print_time = (int) $mode;
    274.     }
    275.    
    276.     /**
    277.      * Установка режима логирования запросов в файл
    278.      *
    279.      * @param int $mode - режим
    280.      */
    281.     public static function setLogError($mode)
    282.     {
    283.         db::init();
    284.         self::$_log_error = (int) $mode;
    285.     }
    286.  
    287.     /**
    288.      * Возвращает общее количество запросов
    289.      *
    290.      * @return int
    291.      */
    292.     public static function getQueries()
    293.     {
    294.         return self::$_nq;
    295.     }    
    296.    
    297.     // объявление методов только PHP ver. < 5.3
    298.    
    299.     /*
    300.      * Возвращает кол-во строк затронутых при запросах DELETE, INSERT или UPDATE
    301.      *
    302.      * @return int
    303.      */
    304.     public static function rowCount()
    305.     {
    306.         return is_object(self::$_statement) ? intval(self::$_statement->rowCount()) : 0;
    307.     }
    308.    
    309.     /*
    310.      * Возвращает ID последней вставленной записи
    311.      *
    312.      * @param string $name
    313.      * @return string
    314.      */
    315.     public static function lastInsertId($name = null)
    316.     {
    317.         return self::init()->lastInsertId($name);
    318.     }
    319.    
    320.     /*
    321.      * Начать транзакцию
    322.      *
    323.      * @return bool
    324.      */
    325.     public static function beginTransaction()
    326.     {
    327.         return self::init()->beginTransaction();
    328.     }
    329.    
    330.     /*
    331.      * Завершить транзакцию
    332.      *
    333.      * @return bool
    334.      */
    335.     public static function commit()
    336.     {
    337.         return self::init()->commit();
    338.     }
    339.    
    340.     /*
    341.      * Отменить транзакцию
    342.      *
    343.      * @return bool
    344.      */
    345.     public static function rollBack()
    346.     {
    347.         return self::init()->rollBack();
    348.     }
    349. } // конец класса db
     
  2. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    Ну собственно теперь можно как стат. методы вызывать:

    PHP:
    1. <?php
    2. echo db::getOne("SELECT COUNT(*) FROM ad WHERE id < ?", 5);
    3. $r1 = db::getRow("SELECT id,name FROM ad WHERE id = ?", 4);
    4. $r2 = db::getAll("SELECT id,name FROM ad WHERE id < ?", 20);
    5.  
    6. db::init('stat'); // другая БД
    7. $r3 = db::getAll("SELECT id,date FROM `2011-06_stat_adv_day` WHERE id < ?", 10);
    8. db::init('default'); // возвращаемся к исходной БД (по умолчанию)
    9. $r4 = db::getRow("SELECT id,name FROM ad WHERE id = ?", 5);
     
  3. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    PDO::query & PDO::exec наверное забыл... с PDO только начал разбираться..

    получается делаю всегда prepared statements для всех запросов, это же не верно?
     
  4. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Смысл prepared в том, чтобы сделать statement для однотипного запроса, и всегда этот statement использовать, когда надо сделать запрос такого вида.
     
  5. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    это я понял, но еще + я получаю возможность использовать плейсхолдеры и автом. экранирование данных, верно? Я в этом тоже вижу несомненный плюс :)
     
  6. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    таким образом, если запрос не изменился, а изменились только данные, то вызывать повторно метод prepare не нужно, нужно просто выполнить его (execute) с др. данными...

    получается просто сохранить посл. запрос в стат. переменной и сравнивать, если посл. был такой - то не нужно его выполнять, правильно ли я мыслю?
     
  7. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    да.
    Вообще можно хранить массив статементов, где ключами будут хэши от запросов, и выбирать для запроса нужный статемент оттуда.
     
  8. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Например в делаешь statement для загрузки пользователя из БД, и для каждой загрузки используешь его. Или для сохранения. Не надо каждый раз создавать одинаковые статементы, в этом фишка.
     
  9. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    [vs]
    спасибо :)
     
  10. Alex_pac

    Alex_pac Активный пользователь

    С нами с:
    11 апр 2011
    Сообщения:
    285
    Симпатии:
    1
    Адрес:
    Россия, Тольятти
    а SET NAMES ? наверно для базы Access не будет работать. ибо она в cp1251 все выдает.
     
  11. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    может быть, если честно Access не использую)
     
  12. posta

    posta Активный пользователь

    С нами с:
    5 июн 2012
    Сообщения:
    1
    Симпатии:
    0
    sylex, А что такое
    Код (Text):
    1. $config = Config::read('database');
    где его брать и как его подключать? Как вообще подключаться с помощью этого класса к бд со своим паролем и логином?
     
  13. d1gi

    d1gi Активный пользователь

    С нами с:
    24 май 2009
    Сообщения:
    326
    Симпатии:
    0
    еще вопрос, если в приложении надо использовать подключения к нескольким БД, то как поступать?
     
  14. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    Код (Text):
    1. <?php
    2.  
    3. /**
    4.  * Класс для работы с БД (PDO)
    5.  *
    6.  * @package     AcFrame
    7.  * @author      Sylex
    8.  * @copyright   2011, AcFrame
    9.  * @version     1.0 (2011/06/08)
    10.  */
    11.  
    12. class db
    13. {
    14.     /**
    15.      * Экземпляр класса
    16.      *
    17.      * @var object
    18.      */
    19.     private static $_instance;
    20.    
    21.     /**
    22.      * Соединения
    23.      *
    24.      * @var array
    25.      */
    26.     private static $_connections = array();
    27.    
    28.     /**
    29.      * Текущая БД (в конфиге)
    30.      *
    31.      * @var string
    32.      */
    33.     private static $_name;
    34.    
    35.     /**
    36.      * Режим отладки
    37.      *
    38.      * @var int
    39.      */
    40.     private static $_debug = 0;
    41.    
    42.     /**
    43.      * Режим записи ошибок в лог
    44.      *
    45.      * @var int
    46.      */
    47.     private static $_log_error = 0;
    48.    
    49.     /**
    50.      * Время выполнения запроса в секундах - для записи запросов в лог (если 0 - отключено)
    51.      *
    52.      * @var int
    53.      */
    54.     private static $_log_sql = 0;
    55.    
    56.     /**
    57.      * Вывод времени выполнения запросов
    58.      *
    59.      * @var int
    60.      */
    61.     private static $_print_time = 0;
    62.    
    63.     /**
    64.      * Счетчик количества запросов
    65.      *
    66.      * @var int
    67.      */
    68.     private static $_nq = 0;
    69.    
    70.     /**
    71.      * Текущее подготовленное выражение
    72.      *
    73.      * @var object
    74.      */
    75.     private static $_statement = null;
    76.    
    77.     /**
    78.      * Подготовленные выражения
    79.      *
    80.      * @var array
    81.      */
    82.     private static $_statements = array();
    83.    
    84.     /**
    85.      * Возвращаемый результат - объект, массив
    86.      *
    87.      * @var int
    88.      */
    89.     private static $_return_result = PDO::FETCH_OBJ; // PDO::FETCH_OBJ, PDO::FETCH_ASSOC, PDO::FETCH_BOTH, PDO::FETCH_NUM
    90.  
    91.     // Запрещаем создавать объект
    92.     final private function __construct() {}
    93.  
    94.     // Запрещаем клонировать объект
    95.     final private function __clone() {}
    96.    
    97.     /*
    98.      * Вызов всех статических методов для PDO (PHP ver. >= 5.3)
    99.      *
    100.      * @param $method - метод
    101.      * @param $args - аргументы
    102.      * @return mixed
    103.      */
    104.     final public static function __callStatic($method, $args)
    105.     {
    106.         $_instance = self::init();
    107.         return call_user_func_array(array($_instance, $method), $args);
    108.     }
    109.  
    110.     /*
    111.      * Возвращает текущий экзмепляр объекта PDO или создает новое соединение
    112.      *
    113.      * @param string $name - имя конфига
    114.      * @return object
    115.      */
    116.     public static function init($name = '')
    117.     {
    118.         // по умолчанию - default
    119.         if (empty($name)) $name = !empty(self::$_name) ? self::$_name : 'default';
    120.         // если нет соединения, или новое
    121.         if (!self::$_instance || self::$_name != $name) {
    122.             // проверка, было ли ранее
    123.             if (isset(self::$_connections[$name])) {
    124.                 self::$_instance = self::$_connections[$name];
    125.                 self::$_name = $name;
    126.                 return self::$_instance;
    127.             }
    128.             // проверка, установленно ли расширение
    129.             if (!class_exists('PDO')) {
    130.                 self::error('Extension PDO not installed');
    131.             }
    132.             // загрузка конфига БД
    133.             $config = Config::read('database');
    134.             $db_config = $config[$name];
    135.             self::$_debug = (int) $db_config['debug'];
    136.             self::$_log_error = (int) $db_config['log_error'];
    137.             self::$_log_sql = isset($db_config['log_sql']) ? floatval($db_config['log_sql']) : 0;
    138.             $params = array(
    139.                 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    140.             );
    141.             if ($db_config['driver'] == 'mysql') {
    142.                 $params[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES '{$db_config['char']}'";
    143.             }
    144.             // постоянное подключение
    145.             if (isset($db_config['persistent']) && $db_config['persistent']) {
    146.                 $params[PDO::ATTR_PERSISTENT] = true;
    147.             }
    148.             // создание нового соединения
    149.             try {
    150.                 @self::$_instance = new PDO("{$db_config['driver']}:host={$db_config['host']};dbname={$db_config['name']}", $db_config['user'], $db_config['pass'], $params);
    151.             } catch (PDOException $e) {
    152.                 self::error('Connection failed: ' . $e->getMessage());
    153.             }
    154.             // запоминаем соединение
    155.             self::$_name = $name;
    156.             self::$_connections[$name] = self::$_instance;
    157.         }
    158.         return self::$_instance;
    159.     }
    160.    
    161.     /*
    162.      * Выполняет запрос с подготовленным выражением (или без) для результата (SELECT)
    163.      *
    164.      * @param string/array $sql - запрос
    165.      * @return bool
    166.      */
    167.     public static function pquery($sql)
    168.     {
    169.         $state = false;
    170.         // подготовка аргументов
    171.         $args = func_get_args();
    172.         if (is_array($sql)) {
    173.             // если передан как массив - вытаскиваем данные
    174.             $args = $args[0];
    175.             if (!isset($args[0])) return false;
    176.             $sql = strval(array_shift($args));
    177.         } else {
    178.             array_shift($args);
    179.         }
    180.         if (isset($args[0]) && is_array($args[0])) { $args = $args[0]; }
    181.         // если пустой запрос
    182.         if (empty($sql)) return false;
    183.        
    184.         if (empty($args)) {
    185.             // выполняем запрос без подготовленного выражения
    186.             try {
    187.                 self::$_statement = self::init()->query($sql);
    188.                 self::$_nq++;
    189.             } catch (PDOException $e) {
    190.                 self::error_sql($e, $sql);
    191.             }
    192.             $state = true;
    193.         } else {
    194.             // выполняем запрос с подготовленным выражением
    195.            
    196.             // старт времени
    197.             if (self::$_print_time == 1 || self::$_log_sql > 0) {
    198.                 timer::start('db_query');
    199.             }
    200.            
    201.             // хэш запроса
    202.             $hash = md5($sql);
    203.             // проверяем, был ли ранее
    204.             if (!isset(self::$_statements[$hash])) {
    205.                 try {
    206.                     // подготавливаем выражение
    207.                     self::$_statement = self::init()->prepare($sql);
    208.                 } catch (PDOException $e) {
    209.                     self::error_sql($e, $sql);
    210.                 }
    211.                 // запоминаем
    212.                 self::$_statements[$hash] = self::$_statement;
    213.             } else {
    214.                 self::$_statement = self::$_statements[$hash];
    215.             }
    216.             if (self::$_statement) {
    217.                 try {
    218.                     // выполняем запрос
    219.                     $state = self::$_statement->execute($args);
    220.                     self::$_nq++;
    221.                 } catch(PDOException $e) {
    222.                     self::error_sql($e, $sql);
    223.                 }
    224.             }
    225.             // логирование по времени
    226.             self::logEnd($sql);
    227.         }
    228.  
    229.         return $state;
    230.     }
    231.    
    232.     /*
    233.      * Выполняет запрос с подготовленным выражением (или без) без результата (INSERT/UPDATE)
    234.      * Возвращает кол-во затронутых строк (измененных/удаленных)
    235.      *
    236.      * @param string/array $sql - запрос
    237.      * @return bool
    238.      */
    239.     public static function exec($sql)
    240.     {
    241.         $count = 0;
    242.         // подготовка аргументов
    243.         $args = func_get_args();
    244.         if (is_array($sql)) {
    245.             // если передан как массив - вытаскиваем данные
    246.             $args = $args[0];
    247.             if (!isset($args[0])) return false;
    248.             $sql = strval(array_shift($args));
    249.         } else {
    250.             array_shift($args);
    251.         }
    252.         if (isset($args[0]) && is_array($args[0])) { $args = $args[0]; }
    253.         // если пустой запрос
    254.         if (empty($sql)) return false;
    255.        
    256.         if (empty($args)) {
    257.             // выполняем запрос без подготовленного выражения
    258.             return self::exec_noprepare($sql);
    259.         } else {
    260.             // выполняем запрос с подготовленным выражением
    261.            
    262.             // старт времени
    263.             if (self::$_print_time == 1 || self::$_log_sql > 0) {
    264.                 timer::start('db_query');
    265.             }
    266.            
    267.             // хэш запроса
    268.             $hash = md5($sql);
    269.             // проверяем, был ли ранее
    270.             if (!isset(self::$_statements[$hash])) {
    271.                 try {
    272.                     // подготавливаем выражение
    273.                     self::$_statement = self::init()->prepare($sql);
    274.                 } catch (PDOException $e) {
    275.                     self::error_sql($e, $sql);
    276.                 }
    277.                 // запоминаем
    278.                 self::$_statements[$hash] = self::$_statement;
    279.             } else {
    280.                 self::$_statement = self::$_statements[$hash];
    281.             }
    282.             if (self::$_statement) {
    283.                 try {
    284.                     // выполняем запрос
    285.                     $count = self::$_statement->execute($args);
    286.                     self::$_nq++;
    287.                 } catch(PDOException $e) {
    288.                     self::error_sql($e, $sql);
    289.                 }
    290.             }
    291.             // логирование по времени
    292.             self::logEnd($sql);
    293.         }
    294.  
    295.         return $count;
    296.     }
    297.    
    298.     /*
    299.      * Выполняет запрос и возвращает кол-во затронутых строк (измененных/удаленных)
    300.      *
    301.      * @param string $sql - запрос
    302.      * @return int - кол-во затронутых строк
    303.      */
    304.     private static function exec_noprepare($sql)
    305.     {
    306.         $count = 0;
    307.         // старт времени
    308.         if (self::$_print_time == 1 || self::$_log_sql > 0) {
    309.             timer::start('db_query');
    310.         }
    311.         try {
    312.             // выполняем запрос
    313.             $count = self::init()->exec($sql);
    314.             self::$_nq++;
    315.         } catch(PDOException $e) {
    316.             self::error_sql($e, $sql);
    317.         }
    318.         // логирование по времени
    319.         self::logEnd($sql);
    320.         return $count;
    321.     }
    322.    
    323.     /*
    324.      * Выполняет запрос и возвращает результат (SELECT)
    325.      *
    326.      * @param string $sql - запрос
    327.      * @return object - PDOStatement
    328.      */
    329.     public static function query($sql)
    330.     {
    331.         // старт времени
    332.         if (self::$_print_time == 1 || self::$_log_sql > 0) {
    333.             timer::start('db_query');
    334.         }
    335.         try {
    336.             // выполняем запрос
    337.             self::$_statement = self::init()->query($sql);
    338.             self::$_nq++;
    339.         } catch(PDOException $e) {
    340.             self::error_sql($e, $sql);
    341.         }
    342.         // логирование по времени
    343.         self::logEnd($sql);
    344.         return self::$_statement;
    345.     }
    346.    
    347.     /**
    348.      * Завершает логирование по времени
    349.      *
    350.      * @param string $sql - запрос
    351.      */
    352.     private static function logEnd($sql)
    353.     {
    354.         if (self::$_print_time == 1 || self::$_log_sql > 0) {
    355.             $time = timer::get('db_query');
    356.             if (self::$_print_time == 1) {
    357.                 // на экран
    358.                 echo $time, '<br />', $sql, '<br /><br />';
    359.             } elseif($time >= self::$_log_sql) {
    360.                 // в файл
    361.                 $file = LOG . date('Y-m-d') . '_db_query.log';
    362.                 $e_file = is_file($file);
    363.                 if ($e_file && !is_writable($file)) @chmod($file, 0777);
    364.                 @file_put_contents($file, date('Y-m-d H:i:s') . ' ' . self::$_name . ' *** ' . $time . ' - ' . $sql . "\n\n", FILE_APPEND);
    365.                 if (!$e_file) @chmod($file, 0777);
    366.             }
    367.         }
    368.     }
    369.  
    370.     /**
    371.      * Возвращает одно значение
    372.      *
    373.      * @param string $sql - запрос
    374.      * @return mixed
    375.      */
    376.     public static function getOne($sql) {
    377.         self::pquery(func_get_args());
    378.         return self::$_statement ? self::$_statement->fetchColumn() : false;
    379.     }
    380.  
    381.     /**
    382.      * Возвращает строку
    383.      *
    384.      * @param string $sql - запрос
    385.      * @return mixed
    386.      */
    387.     public static function getRow($sql) {
    388.         self::pquery(func_get_args());
    389.         return self::$_statement ? self::$_statement->fetch(self::$_return_result) : false;
    390.     }
    391.    
    392.     /*
    393.      * Возвращает ряд строк
    394.      *
    395.      * @param string/array $sql - запрос
    396.      * @return mixed
    397.      */
    398.     public static function getAll($sql)
    399.     {
    400.         self::pquery(func_get_args());
    401.         return self::$_statement ? self::$_statement->fetchAll(self::$_return_result) : false;
    402.     }
    403.    
    404.     /*
    405.      * Обработка исключений для SQL-запроса
    406.      *
    407.      * @param object $e - ошибка
    408.      * @param string $sql - запрос
    409.      */
    410.     private static function error_sql($e, $sql)
    411.     {
    412.         self::error('['.$e->errorInfo[1].'] ' . (isset($e->errorInfo[2]) ? $e->errorInfo[2] : '') . "\n\nQuery: <b>" . $sql . "</b>", $e->errorInfo[0]);
    413.     }
    414.    
    415.     /*
    416.      * Обработка исключений
    417.      *
    418.      * @param string $message - сообщение
    419.      * @param int $code - код ошибки
    420.      */
    421.     private static function error($message, $code = 0)
    422.     {
    423.         if (self::$_log_error == 1) {
    424.             $file = LOG . date('Y-m-d') . '_db_error.log';
    425.             $e_file = is_file($file);
    426.             if ($e_file && !is_writable($file)) @chmod($file, 0777);
    427.             @file_put_contents($file, date('Y-m-d H:i:s') . ' *** ' . $code . ' - ' . $message. "\n\n", FILE_APPEND);
    428.             if (!$e_file) @chmod($file, 0777);
    429.         }
    430.         if (self::$_debug == 0) {
    431.             throw new Error('error in ' . __CLASS__, -1);
    432.         } elseif(self::$_debug == 1) {
    433.             throw new Error($message, $code);
    434.         }
    435.     }
    436.    
    437.     /**
    438.      * Установка кодировки
    439.      *
    440.      * @param string $char - кодировка
    441.      */
    442.     public static function setNames($char)
    443.     {
    444.         db::init();
    445.         self::query("SET NAMES ?", $char);
    446.     }
    447.    
    448.     /**
    449.      * Установка режима отладки
    450.      *
    451.      * @param int $mode - режим
    452.      */
    453.     public static function setDebug($mode)
    454.     {
    455.         db::init();
    456.         self::$_debug = (int) $mode;
    457.     }
    458.    
    459.     /**
    460.      * Установка режима вывода времени выполнения запросов на экран
    461.      *
    462.      * @param int $mode - режим
    463.      */
    464.     public static function setPrintTime($mode)
    465.     {
    466.         self::$_print_time = (int) $mode;
    467.     }
    468.    
    469.     /**
    470.      * Установка режима логирования запросов в файл
    471.      *
    472.      * @param int $mode - режим
    473.      */
    474.     public static function setLogError($mode)
    475.     {
    476.         db::init();
    477.         self::$_log_error = (int) $mode;
    478.     }
    479.    
    480.     /**
    481.      * Установка стиля возвращаемого результата (объект, массив)
    482.      *
    483.      * @param int $res
    484.      */
    485.     public static function setReturnResult($res)
    486.     {
    487.         $res = intval($res);
    488.         if (in_array($res, array(PDO::FETCH_OBJ, PDO::FETCH_ASSOC, PDO::FETCH_BOTH, PDO::FETCH_NUM))) {
    489.             self::$_return_result = (int) $res;
    490.         }
    491.     }
    492.  
    493.     /**
    494.      * Возвращает общее количество запросов за сессию
    495.      *
    496.      * @return int
    497.      */
    498.     public static function getQueries()
    499.     {
    500.         return self::$_nq;
    501.     }  
    502.  
    503.     /*
    504.      * Возвращает кол-во строк затронутых при запросах DELETE, INSERT или UPDATE
    505.      *
    506.      * @return int
    507.      */
    508.     public static function rowCount()
    509.     {
    510.         return self::$_statement ? intval(self::$_statement->rowCount()) : 0;
    511.     }
    512.    
    513.     /*
    514.      * Выполняет вставку записи в БД и возвращает ее ID
    515.      *
    516.      * @param string $sql - запрос, должен содержать %sql%
    517.      * @param array $data - данные для вставки (массив: поле - значение)
    518.      * @param array $types - типы данных (массив: поле - тип) (необязательное)
    519.      *   тип может быть:
    520.      *      str, PDO::PARAM_STR - строка (по умолчанию)
    521.      *      int, PDO::PARAM_INT - число
    522.      *      bool, PDO::PARAM_BOOLEAN - 1/0
    523.      *      null, PDO::PARAM_NULL - null
    524.      *      expr - выражение SQL (не экранируется!)
    525.      *
    526.      * @param array $fields - поля, которые необходимо использовать (необязательное)
    527.      * @return int
    528.      */
    529.     public static function insert($sql, array $data, array $types = array(), array $fields = array())
    530.     {
    531.         try {
    532.             $prep_k = $prep_v = array();
    533.             $fz = empty($fields);
    534.             foreach ($data as $field => $value) {
    535.                 if ($fz || in_array($field, $fields)) {
    536.                     if (!preg_match('|^[a-z0-9_-]+$|i', $field)) {
    537.                         self::error("Insert failed: field {$field} contains invalid characters");
    538.                     }
    539.                     $prep_k[] = "`{$field}`";
    540.                     if (!empty($types[$field]) && $types[$field] === 'expr') {
    541.                         // выражение
    542.                         $prep_v[] = $value;
    543.                     } else {
    544.                         $prep_v[] = ":{$field}";
    545.                     }
    546.                 }
    547.             }
    548.             if (empty($prep_k)) {
    549.                 self::error('Insert failed: empty data');
    550.             }
    551.             // подготавливаем
    552.             $prep = '(' . implode(',', $prep_k) . ') VALUES (' . implode(',', $prep_v) . ')';
    553.             $sql = str_replace('%sql%', $prep, $sql);
    554.            
    555.             // хэш запроса
    556.             $hash = md5($sql);
    557.             // проверяем, был ли ранее
    558.             if (!isset(self::$_statements[$hash])) {
    559.                 // подготавливаем выражение
    560.                 self::$_statement = self::init()->prepare($sql);
    561.                 // запоминаем
    562.                 self::$_statements[$hash] = self::$_statement;
    563.             } else {
    564.                 self::$_statement = self::$_statements[$hash];
    565.             }
    566.            
    567.             // установка данных
    568.             foreach ($data as $field => $value) {
    569.                 if ($fz || in_array($field, $fields)) {
    570.                     if (empty($types[$field])) {
    571.                         $type = PDO::PARAM_STR;
    572.                     } else {
    573.                         $t = $types[$field];
    574.                         // если выражение - пропускаем
    575.                         if ($t === 'expr') continue;
    576.                         if ($t === 'str' || $t === PDO::PARAM_STR) {
    577.                             $type = PDO::PARAM_STR;
    578.                         } elseif ($t === 'int' || $t === PDO::PARAM_INT) {
    579.                             $type = PDO::PARAM_INT;
    580.                         } elseif ($t === 'bool' || $t === PDO::PARAM_BOOL) {
    581.                             $type = PDO::PARAM_BOOL;
    582.                         } elseif ($t === 'null' || $t === PDO::PARAM_NULL) {
    583.                             $type = PDO::PARAM_NULL;
    584.                         } else {
    585.                             self::error('Insert failed: Unknown type for column: ' . $field . "\n\nQuery:\n" . $sql);
    586.                         }
    587.                     }
    588.                     self::$_statement->bindValue($field, $value, $type);
    589.                 }
    590.             }
    591.             // выполняем
    592.             self::$_statement->execute();
    593.         } catch(PDOException $e) {
    594.             self::error($e->getMessage() . "\n\nQuery:\n" . $sql);
    595.         }
    596.         return (int) self::init()->lastInsertId();
    597.     }
    598.    
    599.     /*
    600.      * Выполняет обновление записи в БД
    601.      *
    602.      * @param string $sql - запрос, должен содержать %sql%
    603.      * @param array $data - данные для обновления (массив: 0 - значение, 1 - тип)
    604.      * @param array $types - типы данных (массив: поле - тип) (необязательное)
    605.      *   тип может быть:
    606.      *      str, PDO::PARAM_STR - строка (по умолчанию)
    607.      *      int, PDO::PARAM_INT - число
    608.      *      bool, PDO::PARAM_BOOLEAN - 1/0
    609.      *      null, PDO::PARAM_NULL - null
    610.      *      expr - выражение SQL (не экранируется!)
    611.      *
    612.      * @param array $fields - поля, которые необходимо использовать (необязательное)
    613.      * @param array $data_dop - дополнительные данные
    614.      * @return bool
    615.      */
    616.     public static function update($sql, array $data, array $types = array(), array $fields = array(), array $data_dop = array())
    617.     {
    618.         $res = false;
    619.         try {
    620.             $prep = '';
    621.             $fz = empty($fields);
    622.             foreach ($data as $field => $value) {
    623.                 if ($fz || in_array($field, $fields)) {
    624.                     if (!preg_match('|^[a-z0-9_-]+$|i', $field)) {
    625.                         self::error("Update failed: field {$field} contains invalid characters");
    626.                     }
    627.                     $prep .= ",`{$field}` = ";
    628.                     if (!empty($types[$field]) && $types[$field] === 'expr') {
    629.                         // выражение
    630.                         $prep .= $value;
    631.                     } else {
    632.                         $prep .= ":{$field}";
    633.                     }
    634.                 }
    635.             }
    636.             if (empty($prep)) {
    637.                 self::error('Update failed: empty data');
    638.             }
    639.             // подготавливаем
    640.             $prep = substr($prep, 1);
    641.             $sql = str_replace('%sql%', ' SET ' . $prep, $sql);
    642.            
    643.             // хэш запроса
    644.             $hash = md5($sql);
    645.             // проверяем, был ли ранее
    646.             if (!isset(self::$_statements[$hash])) {
    647.                 // подготавливаем выражение
    648.                 self::$_statement = self::init()->prepare($sql);
    649.                 // запоминаем
    650.                 self::$_statements[$hash] = self::$_statement;
    651.             } else {
    652.                 self::$_statement = self::$_statements[$hash];
    653.             }
    654.            
    655.             // установка данных
    656.             foreach ($data as $field => $value) {
    657.                 if ($fz || in_array($field, $fields)) {
    658.                     if (empty($types[$field])) {
    659.                         $type = PDO::PARAM_STR;
    660.                     } else {
    661.                         $t = $types[$field];
    662.                         // если выражение - пропускаем
    663.                         if ($t === 'expr') continue;
    664.                         if ($t === 'str' || $t === PDO::PARAM_STR) {
    665.                             $type = PDO::PARAM_STR;
    666.                         } elseif ($t === 'int' || $t === PDO::PARAM_INT) {
    667.                             $type = PDO::PARAM_INT;
    668.                         } elseif ($t === 'bool' || $t === PDO::PARAM_BOOL) {
    669.                             $type = PDO::PARAM_BOOL;
    670.                         } elseif ($t === 'null' || $t === PDO::PARAM_NULL) {
    671.                             $type = PDO::PARAM_NULL;
    672.                         } else {
    673.                             self::error('Update failed: Unknown type for column: ' . $field . "\n\nQuery:\n" . $sql);
    674.                         }
    675.                     }
    676.                     self::$_statement->bindValue($field, $value, $type);
    677.                 }
    678.             }
    679.             foreach ($data_dop as $field => $value) {
    680.                 self::$_statement->bindValue($field, $value);
    681.             }
    682.             // выполняем
    683.             $res = self::$_statement->execute();
    684.         } catch(PDOException $e) {
    685.             self::error($e->getMessage() . "\n\nQuery:\n" . $sql);
    686.         }
    687.         return $res;
    688.     }
    689.  
    690.     /*
    691.      * Выполнение стандартных операций на список записей
    692.      *
    693.      * @param string $table - таблица
    694.      * @param string $table_alias - алиас таблицы
    695.      * @param strign $sort - поля сортировки
    696.      * @param int $limit - кол-во записей
    697.      * @param array $sql_add - условия выборки
    698.      * @param array $sql_data - массив данных
    699.      * @param array $sql_select - массив выборок
    700.      * @param array $sql_join - массив присоединенных таблиц
    701.      * @return array/false - результат запроса
    702.      */
    703.     public static function exec_list($table, $table_alias = '', $sort = '', $limit = 0, array $sql_add = array(), array $sql_data = array(), array $sql_select = array(), array $sql_join = array())
    704.     {
    705.         $sql_add = array_unique($sql_add);
    706.         $sql_join = array_unique($sql_join);
    707.         $sql_select = array_unique($sql_select);
    708.         $add_sql = (!empty($sql_add)) ? ' WHERE ' . implode(' AND ', $sql_add) : '';
    709.         $add_join = implode(" \n", $sql_join);
    710.         $select_fields = !empty($sql_select) ? implode(', ', $sql_select) : "{$table_alias}.*";
    711.        
    712.         if (empty($table_alias)) $table_alias = substr($table, 0, 1);
    713.        
    714.         $slimit = '';
    715.         $limit = abs(intval($limit));
    716.         if ($limit > 0) {
    717.             $ENV = Environment::getInstance();
    718.             $ENV['db_count_res'] = self::getOne("SELECT COUNT(*) FROM {$table} {$table_alias} {$add_join} {$add_sql}", $sql_data);
    719.             $offset = dynamic::pager($ENV['db_count_res'], $limit);
    720.             $slimit = "LIMIT {$offset},{$limit}";
    721.         }
    722.        
    723.         $order = !empty($sort) ? "ORDER BY {$table_alias}.{$sort}" : '';
    724.        
    725.         return db::getAll("SELECT
    726.             {$select_fields}
    727.         FROM {$table} {$table_alias}
    728.             {$add_join}
    729.             {$add_sql}
    730.             {$order}
    731.             {$slimit}", $sql_data);
    732.     }
    733.    
    734.     /*
    735.      * Выполнение стандартных операций на получение записи
    736.      *
    737.      * @param string $table - таблица
    738.      * @param string $table_alias - алиас таблицы
    739.      * @param array $sql_add - условия выборки
    740.      * @param array $sql_data - массив данных
    741.      * @param array $sql_select - массив выборок
    742.      * @param array $sql_join - массив присоединенных таблиц
    743.      * @return array/false - результат запроса
    744.      */
    745.     public static function exec_one($table, $table_alias = '', array $sql_add = array(), array $sql_data = array(), array $sql_select = array(), array $sql_join = array())
    746.     {
    747.         $sql_add = array_unique($sql_add);
    748.         $sql_join = array_unique($sql_join);
    749.         $sql_select = array_unique($sql_select);
    750.         $add_sql = (!empty($sql_add)) ? ' WHERE ' . implode(' AND ', $sql_add) : '';
    751.         $add_join = implode(" \n", $sql_join);
    752.         $add_select = !empty($sql_select) ? ', ' . implode(', ', $sql_select) : '';
    753.         $select_fields = !empty($sql_select) ? implode(', ', $sql_select) : "{$table_alias}.*";
    754.         if (empty($table_alias)) $table_alias = substr($table, 0, 1);
    755.        
    756.         return db::getRow("SELECT
    757.             {$select_fields}
    758.         FROM {$table} {$table_alias}
    759.             {$add_join}
    760.             {$add_sql}", $sql_data);
    761.     }
    762. } // конец класса db
    это простой класс для работы с конфигом:

    Код (Text):
    1. <?php
    2.  
    3. /**
    4.  * Для работы с конфигом
    5.  *
    6.  * @package     AcFrame
    7.  * @author      Sylex
    8.  * @copyright   2010, AcFrame
    9.  * @version     1.1 (2011/06/08)
    10.  */
    11.  
    12. class Config
    13. {
    14.  
    15.     /**
    16.      * Контейнер конфигов
    17.      *
    18.      * @var array
    19.      */
    20.     static private $data = array();
    21.  
    22.     /**
    23.      * Чтения конфига
    24.      *
    25.      * @param string $cnf - имя файла конфига
    26.      * @param string $path - путь к директории конфига
    27.      * @param string $method - метод хранения (пока только массив)
    28.      * @return array
    29.      */
    30.     public static function read($cnf, $path = false, $method = 'array') {
    31.         $path = $path ? $path : CONFIG;
    32.         // этот конфиг уже парсился?
    33.         if (isset(self::$data[$cnf])) {
    34.             return self::$data[$cnf];
    35.         } else {
    36.             // пробуем парсить
    37.             if (is_file($path . $cnf . EXT)) {
    38.                 // выбор метода
    39.                 switch ($method) {
    40.                     case 'array':
    41.                         include_once($path . $cnf . EXT);
    42.                         if (isset($data) && is_array($data)) {
    43.                             self::$data[$cnf] = $data;
    44.                         } else {
    45.                             throw new Error('Data config file is incorrect: <b>' . $path . $cnf . EXT . '</b>');
    46.                         }
    47.                     break;
    48.                 }
    49.                 return self::$data[$cnf];
    50.             } else {
    51.                 throw new Error('There is no data file\nMissed: <b>' . $path . $cnf . EXT . '</b>');
    52.             }
    53.         }
    54.     }
    55. }
    Добавлено спустя 2 минуты 44 секунды:
    очень просто

    Код (Text):
    1. db::init('name_db_in_config');
    опять к БД по умолчанию:

    Код (Text):
    1. db::init('default'); // или можно сделать с пустым параметром, или с нужным
    пример конфига:

    Код (Text):
    1. <?php
    2. $data = array(
    3.     'default' => array(
    4.         'driver' => 'mysql',
    5.         'host' => 'localhost',
    6.         'user' => 'root',
    7.         'pass' => '159',
    8.         'name' => 'omsk',
    9.         'char' => 'cp1251',
    10.         'debug' => 1,
    11.         'persistent' => false,
    12.         'log_error' => true,
    13.         'log_sql' => 0.5
    14.     ),
    15.     'stat' => array(
    16.         'driver' => 'mysql',
    17.         'host' => 'localhost',
    18.         'user' => 'root',
    19.         'pass' => '159',
    20.         'name' => 'omsk_stat',
    21.         'char' => 'cp1251',
    22.         'debug' => 1,
    23.         'persistent' => false,
    24.         'log_error' => true,
    25.         'log_sql' => 0.5
    26.     ),
    27.     'geo' => array(
    28.         'driver' => 'mysql',
    29.         'host' => 'localhost',
    30.         'user' => 'root',
    31.         'pass' => '159',
    32.         'name' => 'omsk_geo',
    33.         'char' => 'cp1251',
    34.         'debug' => 1,
    35.         'persistent' => false,
    36.         'log_error' => true,
    37.         'log_sql' => 0.5
    38.     ),
    Добавлено спустя 2 минуты 22 секунды:
    щас наверное еще зададут что за класс timer )) сразу говорю, можно просто закомментить - это для замеров времени)
     
  15. d1gi

    d1gi Активный пользователь

    С нами с:
    24 май 2009
    Сообщения:
    326
    Симпатии:
    0
    т.е. надо постоянно пргыть между подключениями? :)

    Doctrine DBAL смотрится красивее ;)