Опытные разработчики избегают оригинального расширения MySQL из-за его заброшенного статуса в PHP. Однако зарождающиеся веб-разработчики могут совершенно не замечать своего дремлющего прошлого и умирающего будущего.
Вводные учебные пособия по подключению к MySQL из PHP, конечно, в изобилии, как видно из простого «Учебника по php и mysql» в поиске Google. К сожалению, многие из них учат только тому, как использовать оригинальное расширение MySQL. Это направило новых разработчиков, которые хотели бы узнать, как взаимодействовать со своей базой данных, только к одному из трех потенциальных расширений, давая им навык, который вскоре станет бесполезным в будущей основной версии PHP.
В свою очередь, это увеличило количество людей, которые полагаются на расширение и в некоторых случаях будут использовать его в качестве единственного метода доступа к базе данных. Это означает, что «мягкая амортизация» необходима для постепенного отказа от использования расширения с минимальным воздействием для пользователей, которые еще не переключились на более новое расширение.
Таким образом, целью этой статьи из двух частей является повышение осведомленности разработчиков, которые все еще используют расширение MySQL, информирование их о его проблемах и помощь в переключении на альтернативное расширение. В конце концов, кто действительно хочет написать скрипт, зная, что он не будет работать в ближайшей версии PHP? В этой части мы сосредоточимся на MySQLi, а во второй части мы рассмотрим PDO.
Что не так с расширением MySQL?
Помимо того, что в настоящее время он находится в процессе устаревания, может показаться, что с исходным расширением MySQL все в порядке. Окунитесь немного глубже в историю PHP, и легко понять, почему многие разработчики избегают его использования. Расширение поддерживается только с PHP 4.3.1. Это означает, что в последний раз любая новая функциональность была добавлена в расширение MySQL в конце 2002 года. Это то, чего вам не хватает в 10 лет!
Если это не звучит достаточно плохо, последняя версия MySQL API для интеграции с PHP была от MySQL 4.0.0. Это означает, что расширение не поддерживает какие-либо новые функции, добавленные в API на протяжении многих лет MySQL.
Альтернатива № 1: MySQLi — MySQL Improved
Существует два основных варианта взаимодействия с базой данных MySQL. Первым является расширение MySQLi, или MySQL Improved, которое предоставляет как объектно-ориентированный, так и процедурный API.
Разница между процедурным API по сравнению с расширениями MySQL минимальна, но выгоды значительны. С более чем 100 функциями, предоставляемыми MySQLi, он превосходит старое расширение, которое имеет всего 48 функций. Эти новые функции приносят новые функции, и мы рассмотрим некоторые из них сразу после того, как ознакомимся с основами.
Основы MySQLi
Сначала давайте создадим соединение с базой данных MySQL, а затем взаимодействуем с ней, выполняя некоторые основные запросы.
<?php // Procedural API connection method #1 $db = mysqli_connect('host', 'username', 'password'); mysqli_select_db($db, 'database'); // Procedural API connection method #2 $db = mysqli_connect('host', 'username', 'password', 'database'); if (mysqli_connect_errno()) { die(mysqli_connect_error()); } // Object-oriented API connection $db = new MySQLi('host', 'username', 'password', 'database'); if ($db->connect_errno) { die($db->connect_error); }
При использовании процедурной реализации нам предоставляются два способа подключения к базе данных. Первое больше похоже на исходное расширение MySQL, где соединение с хостом отделено от соединения с базой данных, что требует немного больше кода. Второй метод больше похож на объектно-ориентированный интерфейс MySQLi API, где имя базы данных передается в качестве параметра. Затем мы можем проверить, была ли ошибка при попытке подключиться к базе данных, mysqli_connect_errno()
вопрос о возврате mysqli_connect_errno()
. Сообщение об ошибке извлекается с помощью mysqli_connect_error()
.
В объектно-ориентированной реализации мы создаем экземпляр класса MySQLi
и передаем все детали соединения в качестве аргументов конструктора. Затем можно выполнить проверку свойства connect_errno
чтобы убедиться, что произошла ошибка, и соответствующее сообщение об ошибке можно получить из свойства connect_error
.
Теперь давайте проведем некоторые базовые взаимодействия с базой данных.
<?php $name = "O'Reilly"; $email = "In'[email protected]"; $clean = array(); // Procedural API $clean['name'] = mysqli_real_escape_string($db, $name); $clean['email'] = mysqli_real_escape_string($db, $email); mysqli_query($db, "INSERT INTO table_name VALUES (NULL, '{$clean['name']}', '{$clean['email']}')"); mysqli_query($db, "UPDATE table_name SET name = 'Thomas' WHERE email = '{$clean['email']}'"); $result = mysqli_query($db, "SELECT name FROM table_name WHERE email = '{$clean['email']}'"); if ($row = mysqli_fetch_assoc($result)) { echo $row['name']; } else { echo 'No results found.'; } // Object-oriented API $clean['name'] = $db->real_escape_string($name); $clean['email'] = $db->real_escape_string($email); $db->query("INSERT INTO table_name VALUES (NULL, '{$clean['name']}', '{$clean['email']}')"); $db->query("UPDATE table_name SET name = 'Thomas' WHERE email = '{$clean['email']}'"); $result = $db->query("SELECT name FROM table_name WHERE email = '{$clean['email']}'"); if ($row = $result->fetch_assoc()) { echo $row['name']; } else { echo 'No results found.'; }
Основным отличием от оригинального расширения MySQL и процедурного API MySQLi является обязательная передача ссылки на соединение в качестве первого параметра в функции mysqli_*
(полный список всех функций и методов / свойств можно найти в руководстве по PHP ). Это, конечно, отличается от расширения MySQL, где необязательно передавать ссылку на соединение в качестве последнего параметра.
Нам не нужно передавать ссылку на соединение в качестве аргумента методам объекта в объектно-ориентированном подходе, поскольку она поддерживается как часть состояния экземпляра MySQLi
. Кроме того, все методы и свойства, предоставляемые классом MySQLi
также не mysqli_
префикса mysqli_
, а mysqli_stmt_
не mysqli_stmt_
в свойствах и методах класса MySQLi_stmt
.
Что нового в MySQLi?
Теперь, когда мы ознакомились с основами двух API, давайте рассмотрим некоторые из новых функций, которые он представляет: подготовленные операторы, мультизапросы и транзакции.
Подготовленные заявления
Подготовленные операторы, также известные как параметризованные запросы, являются одной из основных функций, представленных этим API. Подготовленные операторы считаются более безопасными, чем функция MySQL mysql_real_escape_string()
поскольку они не подвержены человеческим ошибкам. Если собственная функция экранирования MySQL применяется неправильно, она все равно может оставить дыры в безопасности в веб-приложении.
Параметризованные запросы можно применять так:
<?php $name = "O'Reilly"; $email = "In'[email protected]"; // Procedural API $insQuery = mysqli_prepare($db, 'INSERT INTO table VALUES (NULL, ?, ?)'); mysqli_stmt_bind_param($insQuery, 'ss', $name, $email); mysqli_stmt_execute($insQuery); // Object-oriented API $insQuery = $db->prepare('INSERT INTO table VALUES (NULL, ?, ?)'); $insQuery->bind_param('ss', $name, $email); $insQuery->execute();
При создании подготовленного оператора мы вставляем знаки вопроса (не заключенные в кавычки, в противном случае они будут рассматриваться как строковые значения), чтобы определить, где значения связаны в запросе. Они называются заполнителями, и в этом случае они не называются, поскольку MySQLi не поддерживает именованные заполнители (в отличие от PDO). После того как мы подготовили запрос, мы можем связать параметры.
Сосредоточив внимание на объектно-ориентированном API, первый параметр метода bind_param()
указывает типы аргументов, к которым мы хотели бы привести значения при их привязке. Существует четыре типа: s (строка), i (целое число), d (двойное число) и b (блоб). Все должны использоваться только в нижнем регистре, а количество букв, обозначающих типы параметров, должно соответствовать количеству значений, которые необходимо связать (даже если все значения будут преобразованы одинаково).
Новый параметр в bind_param()
затем передается для каждого значения, которое необходимо bind_param()
с подготовленным запросом. Значения привязки будут приведены соответственно к порядку типов в первом параметре. Затем мы можем выполнить наш подготовленный оператор со всеми значениями, безопасно вставленными в запрос.
Multi-запросы
Следующая важная функция, представленная в MySQLi, — поддержка нескольких операторов. Здесь мы можем объединить операторы SQL в одном запросе, разделив их точкой с запятой, а затем выполнить их все сразу. Это особенно эффективная функция, но она также может быть деструктивной, если перед использованием значение из внешнего источника в запросе не было должным образом экранировано.
С несколькими запросами мы не можем использовать параметризованные запросы, потому что они не могут подготовить несколько операторов за один раз. Заявления должны были бы быть подготовлены индивидуально, что потребовало бы большего количества кода, однако компромисс — большая разборчивость и меньшая вероятность человеческой ошибки.
операции
Последняя функция, которую мы рассмотрим, — это поддержка транзакций, при условии, что вы используете механизм хранения InnoDB. Транзакции часто описываются как имеющие свойства ACID:
- Атомность заявляет, что действие либо полностью произойдет, либо не произойдет вовсе.
- Согласованность — это когда новые данные, поступающие в базу данных, будут соответствовать действующим правилам. Если входящие данные не проверяются, то все они будут возвращены.
- Изоляция относится к состоянию выполняемой транзакции, которая должна оставаться отдельно от других транзакций, пока она не будет полностью завершена.
- Надежность говорит о том, что база данных способна противостоять потере обновленных данных после сбоя, например потери питания. В нем говорится, что как только транзакция будет совершена, она останется таковой.
Транзакции обычно используются, когда у нас есть блок операторов SQL, которые взаимозависимы друг от друга. Это делает все более важным обеспечение того, чтобы либо все они происходили успешно и выполнялись как таковые, либо все терпели неудачу.
Мы можем проверить теорию транзакций, выполнив повторную вставку в таблицу, где для поля установлено ограничение уникального ключа:
<?php mysqli_autoCommit($db, false); $resultA = mysqli_query($db, "INSERT INTO table_name VALUES (NULL, 'Tom', '[email protected]')"); if ($resultA === false) { mysqli_rollback($db); } $resultB = mysqli_query($db, "INSERT INTO table_name VALUES (NULL, 'Tom', '[email protected]')"); if ($resultB === false) { mysqli_rollback($db); } mysqli_commit($db);
При создании транзакции мы сначала вызываем mysqli_autoCommit()
. Это второй параметр (или первый параметр, если вы используете объектно-ориентированный API), должен быть установлен в false, что запрещает базе данных сохранять ваши изменения при выполнении каждого запроса. Это необходимо для предотвращения сохранения каких-либо изменений до того, как вы убедитесь, что транзакция была полностью успешной. Как только изменение было сохранено, его нельзя откатить.
Затем мы выполняем наши запросы, проверяя, не сработали ли они; в случае неудачи изменения не повлияют на базу данных. Однако, если во время транзакции откатов нет, мы можем успешно зафиксировать все изменения с помощью mysqli_commit()
. В приведенном выше примере наш второй оператор вставки потерпел бы неудачу из-за отправки повторяющейся записи, что означает, что в базу данных вообще ничего не будет вставлено.
Резюме
Эта статья продемонстрировала простоту перехода на более новый и более знакомый API MySQLi, а также дает две очень веские причины, по которым вам следует отказаться от использования расширения MySQL: в настоящее время оно устарело (и официально устарело с PHP 5.5.0), а расширение стало крайне устаревшим. Я надеюсь, что это немного облегчит переход на более новый API MySQLi, так что мы наконец сможем увидеть обратную сторону расширения MySQL.
Не забудьте ознакомиться с руководством по PHP для получения дополнительной информации о MySQLi и его библиотеке функций и встроенных классов, и следите за новостями второй части, когда мы рассмотрим PDO.
Изображение через Fotolia