В избранное    Домой   

Вторник,  16 Apr 2024 г., 09:09
Кто не со Мною, тот против Меня; и кто не собирает со Мною, тот расточает. /Евангелие от Матфея/

 Логин:  

 Пароль: 




Анонсы:
=== Дата: 03/09/2011     Автор: Крис Ньюман ===

PHP. Урок 20 Абстрагирование от базы данных

Урок 20. Абстрагирование от базы данных

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

Класс PEAR DB

В PHP есть много готовых решений для уровня абстракции. Но в этом уроке рассматривается класс PEAR DB.

Класс DB реализует абстрагирование от базы данных с помощью расширений для различных баз данных. Все поддерживаемые расширения приводятся в табл. 20.1.

Таблица 20.1. PHP-расширения баз данных, поддерживаемые классом PEAR DB

Расширение База данных
dbase dBase(.dbf)
fbsql FrontBase
ibase Firebird/Interbase
ifx Informix
msql Mini SQL
mssql Microsoft SQL Server
mysql MySQL
mysqli MySQL 4.1 и выше
oci8 Oracle 7, 8, и 9
odbc ODBC
pgsql PostgreSQL
sqlite SQLite
Sybase Sybase

Установка класс DB

Чтобы получить список установленных на Web-сервере классов, в том числе класса DB, нужно выполнить следующую команду:

$ pear list

Для того чтобы установить класс DB, нужно выполнить следующую команду:

$ pear install DB

Нужно помнить, что для установки PEAR на общем Web-сервере, нужно связаться с системным администратором.

После установки необходимое PHP-расширение автоматически активизируется. Поэтому не нужно устанавливать дополнительные драйверы баз данных, чтобы соединиться с различными типами баз при помощи класса DB.

Названия источников данных

Чтобы соединиться с базой данных через класс DB, нужно составить правильное имя источника (DSN). Это строка, в которой задаются параметры соединения. Она напоминает обычные URL, которые используются при доступе на защищенные страницы или при обращении к FTP-серверам.

Следующий DSN используется для соединения с базой данных MySQL, которая работает на localhost:

mysql://chris:mypassword@localhost/mydb

DSN состоит из таких частей: тип базы данных (mysql), имя пользователя (chris), пароль (mypassword), сервер (localhost) и название базы данных (mydb).

Пример полного синтаксиса приводится ниже, а в табл. 20.2 подробно описан каждый параметр:

phptype(dbsyntax)://username:password@protocol+hostspec/datsbase?option=value

Таблица 20.2. Составляющие DSN

Составляющая Описание
phptype Протокол используемой базы данных (например, mysql или oci8)
dbsyntax Необязательный параметр, связанный с SQL-синтаксисом. Для ODBC нужно указать тип базы данных (например, access или mysql)
username Имя пользователя для соединения с базой
password Пароль для доступа к базе данных
protocol Протокол соединения (например, tcp или unix)
hostspec Параметр сервера. Может быть имя_сервера или имя_сервера:порт
database Имя базы банных
option Дополнительные параметры соединения, которые разделяются с помощью &

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

Например, строка соединения SQLite, для которой не нужно username, password и hostspec, выглядит так:

sqlite:///path/to/dbfile

И наоборот, если нужно соединиться с сервером PostgreSQL, который работает на нестандартном порту, нужно задать более сложное выражение:

pgsql://username:password@tcp(hostname:port)/dbname

Использование класс DB

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

include "DB.php";

Тип базы данных. Тип базы данных в параметре phptype соответствует значению из первого столбца в табл. 20.1.

Чтобы соединиться с базой данных, нужно вызвать метод connect класса DB и передать DSN в качестве аргумента:

$db = DB::connect($dsn);

Переменная $db принимает значение объекта класса DB. С его помощью можно выполнять различные операции с базой данных.

Объект базы данных. нельзя создавать новый объект класса DB с помощью оператора new. Для этого нужно воспользоваться DB::connect, который открывает новое соединение с базой данных.

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

$db = DB::connect($dsn);
if (DB::isError($db)) {
    echo "Ошибка соединения " . $db->getMessage();
    exit;
}

Метод isError возвращает true, если аргумент является объектом класса DB_Error. Это свидетельствует о проблеме при соединении с базой данных. После этого можно вызвать метод getMessage объекта класса DB_Error. Он позволяет получить реальную информацию от сервера базы данных.

Ошибки соединения. Переменной $db в любом случае присваивается объект (независимо от того, удачное ли соединение). Он не принимает значение NULL или FALSE.

Выполнение запросов

Чтобы выполнить SQL-запрос с помощью класса DB, используется метод query. Возвращаемое значение зависит от типа выполняемого запроса. В случае ошибки возвращается объект DB_Error. Он позволяет определить ошибку и проанализировать ее (аналогично анализу ошибки при соединении).

В этом примере выполняется запрос из переменной $sql с проверкой наличия ошибки:

$res =$db->query($sql);
if (DB::isError($res)) {
    echo "Ошибка запроса " . $res->getMessage();
    exit;
}

Если запрос состоит из команды INSERT, UPDATE или DELETE, при удачном выполнении на выходе получим константу DB_OK. Количество изменяемых запросом строк можно определить с помощью метода affectedRows из объекта соединения с базой данных:

$sql = "UPDATE mytable SET col2 = 'newvalue' WHERE col1 > 5";
$res = $db->query($sql);
echo $db->affectedRows() . " строк было изменено";

Извлечение выбранных данных

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

Чтобы узнать количество строк и столбцов в наборе данных, нужно использовать, методы numRows и numCols:

$sql = "SELECT * FROM mytable";
$res = $db->query($sql);
echo "В результате запроса найдено " . $res->numRows . " строк " .
    "и " . $res->numCols . " столбцов";

С помощью метода fetchRow объекта DB_Result можно извлечь строку в виде массива. После каждого вызова fetchRow указатель увеличивается на единицу, и извлекается следующая строка данных. Ниже показано, как в цикле извлечь все строки из результата с помощью fetchRow:

$sql = "SELECT col1, col2 FROM mytable";
$res = $db->query($sql);
while ($row = $res->fetchRow()) {
    echo "col1 = " . $row[0] . ", ";
    echo "col2 = " . $row[1] . "<br>";
}

В этом примере нумерация элементов $row начинается с нуля. Все выбираемые столбцы перечислены в выражении SELECT. Поэтому точно известен их порядок. А значит, элемент $row[0] содержит значение col1.

Для метода fetchRow можно задать необязательный аргумент, чтобы изменить индексацию массива. По-умолчанию массив индексируется числами. Это соответствует DB_FETCHMODE_ORDERED. Параметр DB_FETCHMODE_ASSOC, создает ассоциативный массив с ключами, соответствующими названиям столбцов.

Ниже приведен аналог предыдущего примера с использованием ассоциативного массива:

while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
    echo "col1 = " . $row["col1"] . ", ";
    echo "col2 = " . $row["col2"] . "<br>";
}

При необходимости метод fetchRow возвращает объект вместо массива, если передать аргумент DB_FETCHMODE_OBJECT. Вот пример с использованием объектов:

while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) {
    echo "col1 = " . $row->col1 . ", ";
    echo "col2 = " . $row->col2 . "<br>
";
}

Режимы извлечение. Какой режим использовать, зависит от личного предпочтения. Ассоциативный массив или объект удобнее. Кроме того, они повышают читабельность кода. Но если критична скорость, используйте DB_FETCHMODE_ORDERED.

Сокращение вызовов

Если в результате запроса возвращается одна строка с одним столбцом, например результат объединяющей функции, можно воспользоваться методом getOne. Он позволяет выполнить запрос и сразу получит результат. На вход подается строка запроса, а на выходе получаем результат:

$sum = $db->getOne("SELECT sum(col1) FROM mytable");

Есть и другие полезные сокращения. Метод getRow позволяет выполнить запрос и возвращает данные в виде массива. В документации можно найти весь список функций.

Совместимость между базами данных

Уровень абстракции позволяет перенести код управления базой данных на другую платформу. Нужно просто изменить DSN для соединения с базой данных.

Но каждая база данных имеет свои особенности. Поэтому структуру таблиц и SQL-выражения следует выбирать как можно более общими.

Следует использовать только самые простые инструкции языка SQL, которые доступны во всех основных базах данных. Например, SQL с вложенными запросами не поддерживается MySQL 4.0 и ниже. Лучше избегать использования специфических для некоторых баз данных SQL-команд. Например, LIMIT или CREATE SEQUENCE.

Режим совместимости

Класс DB имеет режим совместимости. Он облегчает смену типа баз данных. Директивы настройки для этого режима приводятся в табл. 20.3. Метод setOption позволяет установить нужные параметры, которые комбинируются с помощью логического ИЛИ:

$db->setOptinon('portability',
    DB_PORTABILITY_ERRORS | DB_PORTABILITY_NUMROWS);

Таблица 20.3. Константы режима совместимости

Константа Режим
DB_PORTABILITY_ALL Включить все настройки совместимости
DB_PORTABILITY_NONE Выключить все настройки совместимости
DB_PORTABILITY_DELETE_COUNT Включить принудительный режим подсчета для оператора DELETE. Если нет выражения WHERE, добавить в конце WHERE 1=1
DB_PORTABILITY_ERRORS Включить поддержку одинаковых сообщений об ошибках для различных баз данных
DB_PORTABILITY_LOWERCASE Принудительный перевод названий таблиц и столбцов в нижний регистр
DB_PORTABILITY_NULL_TO_EMPTY Перевести извлеченное значение NULL в пустую строку, потому что некоторые базы данных не различают их
DB_PORTABILITY_NUMROWS Включить поддержку корректной работы метода numRows в Oracle
DB_PORTABILITY_RTRIM Принудительное отсекание разделительных символов в извлечение данных

Работа с кавычками

Метод quoteSmart позволяет заключить значения в кавычки для безопасной вставки в таблицу. Строчные значения заключаются в кавычки, и все нужные символы автоматически преобразовываются.

В следующем примере составляется SQL-выражение при помощи quoteSmart, чтобы не перекрывались символы одиночных кавычек:

$sql = "INSERT INTO phrases (phrase) " .
    "VALUES ( " . $db->quoteSmart($text) . " )";

Ниже показано конечное значение $sql для MySQL-драйвера после выполнения предыдущего выражения:

INSERT INTO phrases (phrase)
VALUES ( Одиночная кавычка \' не перекроится!' )

Вывод и правило разделения зависят от типа базы данных.

Последовательности

Реализация последовательностей может сильно отличаться для различных баз данных. В MySQL, например, используется атрибут AUTO_INCREMENT для столбца. Для MSSQL это будет IDENTITY. В Oracle CREATE SEQUENCE создает объект, который отслеживает значение последовательности для таблицы.

Класс DB использует свой набор функций для управления последовательностями. Поэтому использование поля с автоматическим увеличением не привязывает к одному типу базы данных.

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

Метод объекта базы данных — createSequence позволяет создавать последовательность с уникальным идентификатором. Чтобы получить следующие значение в последовательности, нужно вызвать метод nextId с этим идентификатором.

В примере ниже создается последовательность с именем order_number и выводится первое значение последовательности:

$db->createSequence("order_number");
echo $db->nextId("order_number");

Последующие обращения к nextId возвращают увеличенные для этой последовательности. Если последовательность больше не нужна, ее можно удалить с помощью метода dropSequence.

Ограничение запроса

Ключевое слово LIMIT базы данных MySQL ограничивает количество строк, которые возвращаются в результате запроса. Это нестандартный оператор SQL. Другие базы данных его не поддерживают.

Класс DB содержит метод limitQuery, который эмулирует LIMIT в SQL-выражениях для обеспечения максимальной совместимости. Этот метод вызывается аналогично query, но требует два дополнительных параметра: начальную строку и количество нужных строк.

В следующем примере возвращается пять строк из полученного результата, начиная с 11-ой (нумерация строк начинается с нуля):

$res = $db->limitQuery("SELECT * FROM mytable", 10, 5);

Резюме

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


<<назад

Погода в Рудне
(Волгоградcкая обл.)

Подробнее >>