В зависимости от версии PHP, есть два или три API PHP для доступа к базе данных MySQL. PHP 5 может выбрать между устаревшим расширением mysql, mysqli или PDO_MySQL. PHP 7 удаляет расширение mysql, оставляя только последние два варианта.
Этот гид объясняет терминологию, используемую для описания каждыого API, информацию о выборе API, а также информацию, чтобы помочь выбрать, которую библиотеку применить с MySQL API.
Эта секция обеспечивает введение в варианты, доступные вам, разрабатывая приложение PHP, которое должно взаимодействовать с базой данных MySQL.
Что такое API?
Application Programming Interface, API, определяет классы, методы, функции и переменные, которые должно будет вызвать ваше приложение, чтобы выполнить его желаемую задачу. В случае приложений PHP, которые должны общаться с базами данных, необходимый API обычно выставляется через расширения PHP.
API может быть процедурным или объектно-ориентированным. С процедурным API вы вызываете функции, чтобы выполнить задачи с объектно-ориентированным API, вы порождаете экземпляры классов и затем вызываете методы на полученных объектах. Последний обычно предпочтительный интерфейс, поскольку это более современно и приводит к лучше организованному коду.
Сочиняя приложения PHP, которые должны соединиться с сервером MySQL, есть несколько доступных вариантов API. Этот документ обсуждает то, что доступно и как выбрать лучшее решение для вашего приложения.
Что такое Connector?
В документации MySQL термин connector относится к части программного обеспечения, которое позволяет вашему приложению соединиться с сервером базы данных MySQL. MySQL обеспечивает соединители для множества языков, включая PHP.
Если ваше приложение PHP должно общаться с сервером базы данных, необходимо будет написать код, чтобы выполнить такие действия как соединение с сервером базы данных, запрос и другие связанные с базой данных функции. Программное обеспечение требуется, чтобы обеспечивать API, который ваше приложение будет использовать, а также обращаться со связью между вашим приложением и сервером базы данных, возможно пользуясь другими промежуточными библиотеками в случае необходимости. Это программное обеспечение известно в общем как соединитель, поскольку оно позволяет вашему приложению соединиться с сервером базы данных.
Что такое драйвер?
Драйвер это часть программного обеспечения, разработанного, чтобы общаться с определенным типом сервера базы данных. Драйвер может также вызвать библиотеку, такую как MySQL Client Library или MySQL Native Driver. Эти библиотеки осуществляют протокол низкого уровня, используемый, чтобы общаться с сервером базы данных MySQL.
Посредством примера уровень абстракции базы данных PHP Data Objects (PDO) может использовать один из нескольких определенных для базы данных драйверов. Один из драйверов, которых это имеет в наличии, является PDO MYSQL, который позволяет взаимодействовать с сервером MySQL.
Иногда люди используют термины "соединитель" и "драйвер" попеременно, это может быть запутывающим. В MySQL-связанной документации термин "драйвер" резервируется для программного обеспечения, которое обеспечивает определенную для базы данных часть пакета соединителя.
Что такое расширение?
В документации PHP вы столкнетесь с другим термином
расширение. Код PHP состоит из ядра с
дополнительными расширениями базовой функциональности. MySQL-связанные
расширения PHP, например, mysqli
и
mysql
осуществляются, используя
дополнительную структуру PHP.
Расширение, как правило, выставляет API PHP программисту, чтобы позволить его средствам использоваться программно. Однако некоторые расширения, которые используют дополнительную структуру PHP, не выставляют API PHP программисту.
Расширение драйвера PDO MySQL, например, не выставляет API PHP программисту, но предоставляет интерфейс слою PDO выше его.
Термины "API" и "расширение" не должны быть применены, чтобы означать то же самое, так как расширение может не обязательно выставить API программисту.
PHP предлагает три различных API, чтобы соединиться с MySQL. Ниже мы показываем API, обеспеченные расширениями mysql, mysqli и PDO. Каждый фрагмент кода создает связь с сервером MySQL, работающим на "example.com", используя пользователя "user" и пароль "password".
Пример 2.1. Сравнения трех MySQL API
<?php // mysqli $mysqli = new mysqli("example.com", "user", "password", "database"); $result = $mysqli->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL"); $row = $result->fetch_assoc(); echo htmlentities($row['_message']); // PDO $pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password'); $statement = $pdo->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL"); $row = $statement->fetch(PDO::FETCH_ASSOC); echo htmlentities($row['_message']); // mysql $c = mysql_connect("example.com", "user", "password"); mysql_select_db("database"); $result = mysql_query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL"); $row = mysql_fetch_assoc($result); echo htmlentities($row['_message']); ?>
Рекомендуемый API
Рекомендуется использовать mysqli или PDO_MySQL. Не рекомендуется использовать старый mysql для новой разработки, поскольку это устарело в PHP 5.5.0 и было удалено в PHP 7. Подробная матрица сравнения особенности обеспечивается ниже. Общая производительность всех трех расширений считается равной. Выполнение расширения вносит только долю полного времени выполнения веб-запроса PHP. Часто воздействие всего 0.1%.
Сравнение особенности
ext/mysqli | PDO_MySQL | ext/mysql | |
---|---|---|---|
Введено в версии PHP | 5.0 | 5.1 | 2.0 |
Включено в PHP 5.x | Да | Да | Да |
Включено в PHP 7.x | Да | Да | Нет |
Статус разработки | Active | Active | Обслуживание только в 5.x, удалено в 7.x |
Lifecycle | Active | Active | Устарело в 5.x, удалено в 7.x |
Рекомендуемый для новых проектов | Да | Да | Нет |
Интерфейс OOP | Да | Да | Нет |
Процедурный интерфейс | Да | Нет | Да |
API поддерживает неблокирующие асинхронные запросы с mysqlnd | Да | Нет | Нет |
Постоянные связи | Да | Да | Да |
API поддерживает Charsets | Да | Да | Да |
API поддерживает подготовленные запросы на сервере | Да | Да | Нет |
API поддерживает подготовленные запросы на клиенте | Нет | Да | Нет |
API поддерживает хранимые процедуры | Да | Да | Нет |
API поддерживает мультизапросы | Да | Most | Нет |
API поддерживает транзакции | Да | Да | Нет |
Транзакциями можно управлять с SQL | Да | Да | Да |
Поддержка полной функциональности MySQL 5.1+ | Да | Most | Нет |
Расширения mysqli, PDO_MySQL и mysql являются легкими обертками сверху
библиотеки клиента C. Расширения могут пользоваться библиотекой
mysqlnd или
libmysqlclient
.
Выбор библиотеки является решением времени компиляции.
Библиотека mysqlnd часть дистрибутива PHP с версии 5.3.0. Это предлагает такие особенности, как ленивые связи и кэширование запроса, особенности, которые недоступны с libmysqlclient, так что применение mysqlnd очень рекомендовано. См. mysqlnd для дополнительных деталей и списка особенностей и функциональности, которые она предлагает.
Пример 2.2. Команды настройки для использования mysqlnd или libmysqlclient
// Recommended, compiles with mysqlnd $ ./configure --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd \ --with-mysql=mysqlnd // Alternatively recommended, compiles with mysqlnd as of PHP 5.4 $ ./configure --with-mysqli --with-pdo-mysql --with-mysql // Not recommended, compiles with libmysqlclient $ ./configure --with-mysqli=/path/to/mysql_config \ --with-pdo-mysql=/path/to/mysql_config \ --with-mysql=/path/to/mysql_config
Сравнение возможностей библиотек
Рекомендуется пользоваться библиотекой mysqlnd вместо библиотеки MySQL Client Server (libmysqlclient). Обе библиотеки поддерживаются и постоянно улучшаются.
MySQL native driver (mysqlnd) | Библиотека MySQL client server (
libmysqlclient ) | |
---|---|---|
Часть сборки PHP | Да | Нет |
Введена в версии PHP | 5.3.0 | N/A |
Лицензия | PHP License 3.01 | Dual-License |
Статус разработки | Active | Active |
Lifecycle | No end announced | No end announced |
PHP 5.4 и выше, используется по умолчанию (для всех расширений MySQL) | Да | Нет |
PHP 5.3, используется по умолчанию (для всех расширений MySQL) | Нет | Да |
Поддежка сжатого протокола | Да (5.3.1+) | Да |
Поддежка SSL | Да (5.3.3+) | Да |
Поддежка именованных каналов | Да (5.3.4+) | Да |
Да | Нет | |
Исполнительная статистика | Да | Нет |
LOAD LOCAL INFILE понимает директиву open_basedir directive | Да | Нет |
Родная система управления памятью PHP например, следует лимитам памяти PHP) | Да | Нет |
Возвратите числовую колонку как double (COM_QUERY) | Да | Нет |
Возвратите числовую колонку как последовательность (COM_QUERY) | Да | Да |
Plugin API | Да | Limited |
Чтение-запись разделены для MySQL Replication | Да с плагином | Нет |
Выравнивание нагрузки | Да с плагином | Нет |
Fail over | Да с плагином | Нет |
Ленивые связи | Да с плагином | Нет |
Кэширование запроса | Да с плагином | Нет |
Прозрачные манипуляции запроса (например, auto-EXPLAIN или мониторинг) | Да с плагином | Нет |
Автоматическое пересоединение | Нет | Опционально |
Эти понятия определены для драйверов MySQL для PHP.
Запросы используют буферизированный способ по умолчанию. Это означает, что результаты запроса немедленно передаются от MySQL Server в PHP и затем сохранены в памяти PHP. Это позволяет такие дополнительные операции, как подсчет количества строк и перемещения указателя текущего результата. Это также позволяет выпускать дальнейшие запросы на той же самой связи, работая над набором результатов. Оборотная сторона буферизированного способа то, что большие наборы результатов могли бы потребовать довольно большой памяти. Память будет сохранена занятой, пока все ссылки на набор результатов не будут сброшены, или набор результатов не будет явно освобожден, что автоматически произойдет во время конца запроса. Терминология "хранение результата" также используется для буферизированного способа, поскольку набор результатов сохранен сразу.
Используя libmysqlclient как библиотеку, предел памяти PHP не посчитает память используемой для наборов результатов, если данные не будут принесены в переменные PHP. С mysqlnd память будет включать полный набор результатов.
Небуферизированные запросы MySQL выполняют запрос и затем возвращают ресурс в то время как данные все еще ждут на сервере MySQL. Это использует меньше памяти на PHP-стороне, но может увеличить нагрузку на сервере. Если полный набор результатов не был принесен от сервера, никакие дальнейшие запросы нельзя послать по той же самой связи. Небуферизированные запросы могут также упоминаться как "использование результата".
Буферизованные запросы должны использоваться в случаях, где вы ожидаете только ограниченный набор результатов или должны знать сумму возвращенных строк прежде, чем прочитать все строки. Небуферизированный способ должен использоваться, когда вы ожидаете большие результаты.
Поскольку буферизированные запросы являются умолчанием, примеры ниже продемонстрируют, как выполнить небуферизированные запросы с каждым API.
Пример 2.3. Пример небуферизированного запроса: mysqli
<?php $mysqli= new mysqli("localhost", "my_user", "my_password", "world"); $uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT); if ($uresult) { while ($row = $uresult->fetch_assoc()) { echo $row['Name'] . PHP_EOL; } } $uresult->close(); ?>
Пример 2.4. Пример небуферизированного запроса: pdo_mysql
<?php $pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_pass'); $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $uresult = $pdo->query("SELECT Name FROM City"); if ($uresult) { while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) { echo $row['Name'] . PHP_EOL; } } ?>
Пример 2.5. Пример небуферизированного запроса: mysql
<?php $conn = mysql_connect("localhost", "my_user", "my_pass"); $db = mysql_select_db("world"); $uresult = mysql_unbuffered_query("SELECT Name FROM City"); if ($uresult) { while ($row = mysql_fetch_assoc($uresult)) { echo $row['Name'] . PHP_EOL; } } ?>
Идеально надлежащий набор символов будет установлен на уровне сервера, выполнение этого описано в разделе Character Set Configuration в руководстве на MySQL Server. Альтернативно, каждый MySQL API предлагает метод, чтобы установить набор символов во время выполнения.
Набор символов должен быть понят и определен, поскольку он имеет влияние
на каждом действии и включает последствия безопасности. Например, экранировка
(например,
mysqli_real_escape_string
в mysqli,
mysql_real_escape_string
в mysql и
PDO::quote
в PDO_MySQL) будет придерживаться этой настройки.
Важно понять, что эти функции не будут использовать набор символов, который
определяется с запросом, таким образом, например, следующее
не будет иметь эффекта:
Пример 2.6. Проблемы с урегулированием набора символов с SQL
<?php $mysqli = new mysqli("localhost", "my_user", "my_password", "world"); // Will NOT affect $mysqli->real_escape_string(); $mysqli->query("SET NAMES utf8"); // Will NOT affect $mysqli->real_escape_string(); $mysqli->query("SET CHARACTER SET utf8"); // But, this will affect $mysqli->real_escape_string(); $mysqli->set_charset('utf8'); // But, this will NOT affect it (utf-8 vs utf8) -- don't use dashes here $mysqli->set_charset('utf-8'); ?>
Ниже даны примеры, которые демонстрируют, как правильно изменить набор символов во время выполнения, используя каждый API.
Поскольку имена наборов символов в MySQL не содержат тире, последовательность "utf8" действительна в MySQL, чтобы установить набор символов в UTF-8. Последовательность "utf-8" не действительна, поскольку использование "utf-8" не изменит набор символов.
Пример 2.7. Установка набора символов: mysqli
<?php $mysqli = new mysqli("localhost", "my_user", "my_password", "world"); printf("Initial character set: %s\n", $mysqli->character_set_name()); if (!$mysqli->set_charset('utf8')) { printf("Error loading character set utf8: %s\n", $mysqli->error); exit; } echo "New character set information:\n"; print_r($mysqli->get_charset()); ?>
Пример 2.8. Установка набора символов: pdo_mysql
Примечание: Это работает только с PHP 5.3.6.
<?php $pdo = new PDO("mysql:host=localhost;dbname=world;charset=utf8", 'my_user', 'my_pass'); ?>
Пример 2.9. Установка набора символов: mysql
<?php $conn = mysql_connect("localhost", "my_user", "my_pass"); $db = mysql_select_db("world"); echo 'Initial character set: ' .mysql_client_encoding($conn) . "\n"; if (!mysql_set_charset('utf8', $conn)) { echo "Error: Unable to set the character set.\n"; exit; } echo 'Your current character set is: ' .mysql_client_encoding($conn); ?>