ProfiPHPProfiPHP
Категория: Полезное в PHP

Класс для работы с базой данных MySQL

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

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

Конфигурационные настройки класса

Для работы данного класса необходимо иметь конфигурационные настройки, которые касаются непосредственно сервера баз данных:
define( "DBHOST", "localhost" );
define( "DBNAME", "base" );
define( "DBUSER", "root" );
define( "DBPASS", "password" );
define( "COLLATE", "utf8" );
Опишем основные константы:

- DBHOST содержит имя сервера MySQL;

- DBNAME содержит имя базы данных;

- DBUSER содержит имя пользователя;

- DBPASS содержит пароль пользователя базы данных;

- COLLATE кодировка по-умолчанию.

Далее опишем функции класса.

Свойства объекта класса MySQLi

Как известно, объект - это совокупность данных (свойств) и функций (методов) для их обработки. Свойства и методы называются членами класса. В самом начале опишем переменные свойства данного класса.
var $db_object = false;
var $query_num = 0;
var $query_list = array( );
var $mysql_version = '';
var $MySQL_time_taken = 0;
var $query_object = false;
Опишем основные переменные:

- Переменная $db_object будет хранить открытое соединение с базой данных. По умолчанию значение False.

- В переменной $query_num будет хранится число выполненных запросов к базе данных. Это полезно для оптимизации скрипта и определения нагрузки. По умолчанию равна 0.

- Массив $query_list будет хранить список запросов, их время выполнения и сам запрос. Данная переменная служит исключительно для наладочных целей, поэтому ее использование будет оправдано только при работе администратора сайта.

- В переменной $mysql_version будет хранится версия сервера базы данных MySQL. Эти данные будут интересны, например, при тестировании скорости работы различных версий.

- Переменная $MySQL_time_taken будет сохранять общее время, которое тратится на запросы к базе данных. По умолчанию равна 0.

- Переменная $query_object сохраняет значение выполнения запроса к базе данных.

Далее будут следовать необходимые функции, и начнем с функции определения реального времени:
function get_real_time(  ) {
return microtime( true );
}
Подключение к базе данных MySQL

Следующим этапом будет функция подключения к базе данных:
function connect( $db_user, $db_pass, $db_name, $db_location )
{
$db_location = explode( ":", $db_location );
if ( isset( $db_location[1] ) ) {
$this->db_object = @mysqli_connect( $db_location[0], $db_user, $db_pass, $db_name, $db_location[1] );
}
else {
$this->db_object = @mysqli_connect( $db_location[0], $db_user, $db_pass, $db_name );
}
if ( ! $this->db_object ) {
$this->display_error( mysqli_connect_error( ), '1' );
}
$this->mysql_version = mysqli_get_server_info( $this->db_object );
mysqli_query( $this->db_object, "SET NAMES '" . COLLATE . "'" );
mysqli_set_charset( $this->db_object, "utf8" );
return true;
}
Данная функция принимает в качестве параметров имя пользователя, пароль, имя базы данных и хоста.

В зависимости от наличия порта в имени хоста, будет выполнен один из двух вариантов подключения.

Если подключение завершится ошибкой, тогда сработает функция Display_error, которая будет описана далее.
if ( ! $this->db_object ) {
$this->display_error( mysqli_connect_error( ), '1' );
}
В переменную Mysql_version будет записано значение версии базы данных:
$this->mysql_version = mysqli_get_server_info( $this->db_object );
И последнее, что делает данная функция, это устанавливает необходимую кодировку для работы:
mysqli_query( $this->db_object, "SET NAMES '" . COLLATE . "'" );
mysqli_set_charset( $this->db_object, "utf8" );
Функция выполнения запроса MySQL

Далее следует функция выполнения запроса к базе данных.
function query( $query )
{
$time_before = $this->get_real_time( );
if ( ! $this->db_object ) {
$this->connect( DBUSER, DBPASS, DBNAME, DBHOST );
}
if ( ! ( $this->query_object = mysqli_query( $this->db_object, $query ) ) ) {
$this->display_error( mysqli_error( $this->db_object ), mysqli_errno( $this->db_object ), $query );
}
$this->MySQL_time_taken += $this->get_real_time( ) - $time_before;
$this->query_list[ ] = array( 'time' => ( $this->get_real_time( ) - $time_before ), 'query' => $query, 'num' => ( count( $this->query_list ) + 1 ) );
$this->query_num++;
return $this->query_object;
}
Именно данная функция будет выполнять основные действия с базой данных: добавление, удаление, редактирование информации.

Сначала функция записывает в переменную $time_before реальное время начала работы функции:
$time_before = $this->get_real_time(  )
Далее выполняет подключение к базе данных, если оно не установлено предыдущим вызовом данной функции.
if ( ! $this->db_object ) {
$this->connect( DBUSER, DBPASS, DBNAME, DBHOST );
}
Далее функция выполняет запрос, и в случае его завершения с ошибкой, выдает сообщение об этом:
if ( ! ( $this->query_object = mysqli_query( $this->db_object, $query ) ) ) {
$this->display_error( mysqli_error( $this->db_object ), mysqli_errno( $this->db_object ), $query );
}
Далее функция рассчитывает время выполнения запроса, и добавляет его к уже существующему. Переменная MySQL_time_taken будет сохранять общее время выполнения всех запросов:
$this->MySQL_time_taken += $this->get_real_time(  ) - $time_before;
Далее заполняем массив $query_list, который будет хранить список запросов, их время выполнения и сам запрос.
$this->query_list[ ] = array( 'time' => ( $this->get_real_time(  ) - $time_before ), 'query' => $query, 'num' => ( count( $this->query_list ) + 1 ) );
Последнее действия функции является подсчет количества всех запросов и возвращения результата выполнения:
$this->query_num++;
return $this->query_object;
Функция возврата автоматически генерируемого ID

Далее следует функция возврата автоматически генерируемого ID, используя последний запрос.
function insert_id(  ) {
return mysqli_insert_id( $this->db_object );
}
Данная функция может пригодится записывая уникальное значение идентификатора ID пользователя при регистрации, то есть при добавлении данных в базу данных.

Функция Mysqli_insert_id возвращает ID, генерируемый запросом к таблице, которая содержит колонку с атрибутом AUTO_INCREMENT.

Извлечение результирующего ряда в виде ассоциативного массива

Следующей функцией будет функция извлечения результирующего ряда в виде ассоциативного массива.
function get_row( $query_object = '' )
{
if ( $query_object == '' ) {
$query_object = $this->query_object;
}
return mysqli_fetch_assoc( $query_object );
}
Возвращает ассоциативный массив, соответствующий результирующей выборке или NULL, если других рядов не существует.

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

Освобождение памяти занятой результатам запроса

Опишем функцию освобождения памяти занятой результатам запроса:
function free( $query_object = '' )
{
if ( $query_object == '' ) {
$query_object = $this->query_object;
}
@mysqli_free_result( $query_object );
}
Если в параметре пустая строка, тогда будет освобождена память последнего запроса к базе данных, иначе запрос, который содержится в параметре функции.

Функция мультизапроса

Опишем функцию, которая выполняет мультизапит к базе данных:
function super_query( $query, $multi = false )
{
if ( ! $multi ) {
$this->query( $query );
$data = $this->get_row( );
$this->free( );
return $data;
}
else {
$this->query( $query );
$rows = array( );
while( $row = $this->get_row( ) ) {
$rows[ ] = $row;
}
$this->free( );
return $rows;
}
}
Данная функция принимает в качестве параметра запрос к базе данных. Второй аргумент функции является логический тип, который по умолчанию принимает значение False.

Если значение второго аргумента False, функция возвращает одну строку запроса. Если значение True - тогда возвращается массив результатов. Также данная функция освобождает память, занятую результатам запроса.

Получаем число строк, полученных предыдущей операцией

Опишем процедуру получения числа строк, затронутых предыдущей операцией запроса к базе данных:
function get_affected_rows(  ) {
return mysqli_affected_rows( $this->db_object );
}
Данная функция возвращает число строк, полученных в последних INSERT, UPDATE, REPLACE или DELETE запросах.

Результатом работы функции является целое число. Если оно большее нуля, значит одна из вышеописанных операция закончилась успешно. Ноль означает, что запросу вида UPDATE не обновлен ни одной записи, или ни один строка не соответствует условию WHERE в запросе, или запрос еще не был выполнен.

Получаем число рядов в результирующей выборке

Рассмотрим функцию получения числа рядов в результирующей выборке:
function num_rows( $query_object = '' )
{
if ( $query_object == '' ) {
$query_object = $this->query_object;
}
return mysqli_num_rows( $query_object );
}
Если параметр пустая строка, тогда будет возвращен массив последнего запроса к базе данных, иначе запрос, который содержится в параметре функции.

Выборка одной строки из результирующего набора

Далее следует функция выборки одной строки из результирующего набора и добавление ее в ассоциативный массив.
function get_array( $query_object = '' )
{
if ( $query_object == '' ) {
$query_object = $this->query_object;
}
return mysqli_fetch_array( $query_object );
}
Если параметр пустая строка, тогда будет возвращен массив последнего запроса к базе данных, иначе запрос, который содержится в параметре функции.

Функция экранирование спецсимволов в строке

Еще одна функция данного класса является функция экранирования спецсимволов в строке:
function safesql( $source )
{
if ( ! $this->db_object ) {
$this->connect( DBUSER, DBPASS, DBNAME, DBHOST );
}
if ( $this->db_object ) {
return mysqli_real_escape_string( $this->db_object, $source );
}
else {
return addslashes( $source );
}
}
Данная функция возвращает строку, в которой перед каждым спецсимволов добавлен обратный слэш (\), для дальнейшего использования этой строки в запросе к базе данных. Экранируются одиночные кавычки ('), двойные кавычки ("), обратный слеш (\) и NUL (байт NULL).

Закрытие ранее открытого соединения с базой данных

Функция Close класса для работы с базой данных закрывает ранее открытое соединение с базой данных.
function close(  ) {
@mysqli_close( $this->db_object );
}
Функция вывода ошибок

Далее следует функция вывода ошибок, благодаря которой можно четко обнаружить местоположение ошибки:
function display_error( $error, $error_num, $query = '' )
{
$query = htmlspecialchars( $query, ENT_QUOTES, 'UTF-8' );
$error = htmlspecialchars( $error, ENT_QUOTES, 'UTF-8' );
$trace = debug_backtrace( );
$level = 0;
if ( @$trace[1]['function'] == "query" ) $level = 1;
if ( @$trace[2]['function'] == "super_query" ) $level = 2;
echo '
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>MySQL Fatal Error</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<table border="1">
<tr>
<td colspan="2" align="center">MySQL Error!</td>
</tr>
<tr>
<td>MySQL error in file:</td>
<td>'.$trace[$level]['file'].' at line '.$trace[$level]['line'].'</td>
</tr>
<tr>
<td>Error Number:</td>
<td>'.$error_num.'</td>
</tr>
<tr>
<td>The Error returned was:</td>
<td>'.$error.'</td>
</tr>
<tr>
<td>SQL query:</td>
<td>'.$query.'</td>
</tr>
</table>
</body>
</html>';
exit( );
}
Сначала обрабатываем вывод ошибок, а именно преобразуем специальные символы в HTML-сущности:
$query = htmlspecialchars( $query, ENT_QUOTES, 'UTF-8' );
$error = htmlspecialchars( $error, ENT_QUOTES, 'UTF-8' );
Далее запускаем функцию Debug_backtrace, которая возвращает массив вложенных ассоциативных массивов:
$trace = debug_backtrace(  );
Поскольку вызов функции Query содержится в функции Super_query, содержание массивов будет всегда строго по порядку:
Array
(
[0] => Array
(
[file] => classes\mysqli.php
[line] => 43
[function] => display_error
...
)
[1] => Array
(
[file] => classes\mysqli.php
[line] => 76
[function] => query
...
)
[2] => Array
(
[file] => file.php
[line] => 17
[function] => super_query
)
)
Благодаря данной функции, мы точно узнаем имя файла, номер строки с ошибкой, номер самой ошибки с текстовым представлением и запрос, который содержит ошибку.

Ну вот и подошел к концу класс для работы с базой данных MySQL.

Опишем основные возможности класса и их реализацию.

Сначала необходимо создать экземпляр класса:
$db = new db;
Добавление записей в таблицу:
$email = 'first@mail.ru';
$password = 'abc';
$db->query( "INSERT INTO `test` ( `email`, `password` ) VALUES ( '{$email}', '{$password}' )" );
Удаление записи:
$db->query( "DELETE FROM `test` WHERE password = 'mypassword'" );
Автоматически генерируемый ID последний запроса:
$id = $db->insert_id(  );
Обновление записей:
$email = 'myname@mail.ru';
$password = 'abc';
$id = '3';
$db->query( "UPDATE `test` SET `email` = '{$email}', `password` = '{$password}' WHERE ( id = '{$id}' )" );
Выборка данных:
$password = 'abc';
$row = $db->query( "SELECT email, password FROM `test` WHERE password = '{$password}'" );
echo '<pre>';
print_r( $row );
echo '</pre>';
echo $db->num_rows( );
Результат выполнения:
mysqli_result Object
(
[current_field] => 0
[field_count] => 2
[lengths] =>
[num_rows] => 1
[type] => 0
)
1
Второй вариант:
$password = 'abc';
$row = $db->super_query( "SELECT email, password FROM `test` WHERE password = '{$password}'", true );
echo '<pre>';
print_r( $row );
echo '</pre>';
echo $db->get_affected_rows( );
Результат выполнения:
Array
(
[0] => Array
(
[email] => myname@mail.ru
[password] => vasya
)
)
1
Третий вариант:
$password = 'abc';
$db->query( "SELECT email, password FROM `test` WHERE password = '{$password}'" );
$row = $db->get_row( );
echo '<pre>';
print_r( $row );
echo '</pre>';
Результат:
Array
(
[email] => myname@mail.ru
[password] => vasya
)
Проверка существования уникальной записи:
$db->query( "SELECT `id` FROM `table` WHERE `id` = '999'" );
if ( $db->num_rows( ) ) {
...
}
Проверка существования нескольких подходящих записей:
$row = $db->super_query( "SELECT COUNT(*) as count FROM `table` WHERE `name` = 'php'" );
if ( $row['count'] > 2 ) {
...
}

Добавить комментарий

Имя:
Текст комментария: