W3docs

PHP MySQLi

Расширение PHP MySQLi: подключение к MySQL, безопасные запросы с подготовленными выражениями, обработка ошибок и сравнение MySQLi с PDO.

MySQLi («MySQL Improved») — это расширение PHP для подключения к базе данных MySQL или MariaDB, выполнения запросов и чтения результатов. В этой статье рассказывается, что представляет собой расширение, как устанавливать соединение, как безопасно выполнять запросы SELECT/INSERT/UPDATE и когда выбирать MySQLi, а не PDO.

Что такое расширение MySQLi?

Расширение MySQLi пришло на смену устаревшим (и ныне удалённым) функциям mysql_*. Оно добавляет возможности, которых в оригинальном расширении не было: подготовленные выражения, транзакции, множественные запросы и полноценную поддержку аутентификации MySQL 4.1+. Расширение поставляется в комплекте с PHP и по умолчанию включено на большинстве установок.

MySQLi предоставляет одну и ту же функциональность через два интерфейса:

  • Объектно-ориентированный — вы работаете с объектом mysqli и вызываете методы наподобие $mysqli->query(). Именно этот стиль используется в большинстве современного кода и в данной статье.
  • Процедурный — вы вызываете функции вроде mysqli_connect() и mysqli_query() и передаёте соединение в качестве первого аргумента.

Оба варианта делают абсолютно одно и то же; выберите один и придерживайтесь его. Объектно-ориентированная форма короче и читается естественнее.

Подключение к базе данных

Соединение представлено объектом mysqli. Вы создаёте его, передавая хост, имя пользователя, пароль и имя базы данных конструктору, а затем проверяете успешность подключения перед выполнением каких-либо действий:

<?php
$mysqli = new mysqli("localhost", "username", "password", "my_database");

// Always check the connection before using it.
if ($mysqli->connect_error) {
    die("Failed to connect to MySQL: " . $mysqli->connect_error);
}

// Recommended: use UTF-8 so accented characters and emoji are stored correctly.
$mysqli->set_charset("utf8mb4");

echo "Connected successfully";
?>

Свойство connect_error содержит понятное человеку сообщение в случае неудачного подключения (или null при успехе). Вызов set_charset() сразу после подключения помогает избежать скрытых проблем с кодировкой в дальнейшем. Подробнее об открытии соединения читайте в PHP mysqli_connect() и справочнике connect().

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

После подключения метод query() выполняет SQL и возвращает объект результата, по которому можно итерироваться. fetch_assoc() возвращает одну строку за раз в виде ассоциативного массива или null, когда строк больше нет:

<?php
$result = $mysqli->query("SELECT name, email FROM users");

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        echo "Name: " . $row["name"] . " - Email: " . $row["email"] . "<br>";
    }
} else {
    echo "No users found.";
}

$result->free();   // release the result set
$mysqli->close();  // close the connection when you are done
?>

num_rows показывает количество возвращённых строк, чтобы вы могли вывести понятное сообщение, если запрос не вернул результатов. Больше примеров запросов смотрите в PHP MySQL Select Data.

Подготовленные выражения (безопасный способ работы с вводом)

Никогда не вставляйте пользовательский ввод прямо в строку запроса — именно так происходит SQL-инъекция. Подготовленное выражение передаёт SQL и данные отдельно, поэтому база данных воспринимает ввод строго как значение, а не как исполняемый SQL.

Вы записываете ?-заполнители, prepare() -ите выражение, затем привязываете реальные значения через bind_param():

<?php
$age = 18;

$stmt = $mysqli->prepare("SELECT name, email FROM users WHERE age > ?");
$stmt->bind_param("i", $age);   // "i" = integer (s = string, d = double, b = blob)
$stmt->execute();

$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    echo "Name: " . $row["name"] . " - Email: " . $row["email"] . "<br>";
}

$stmt->close();
?>

Первый аргумент bind_param() — это строка типов: один символ на каждый заполнитель — i (integer), s (string), d (double/float) или b (blob). Остальные аргументы — это значения в том же порядке.

Примечание: get_result() требует драйвера mysqlnd, который используется по умолчанию в современных версиях PHP. Если в вашей сборке его нет, используйте bind_result() для привязки столбцов к переменным.

Подробное руководство смотрите в PHP MySQL Prepared Statements.

Вставка и обновление данных

Тот же шаблон с подготовленными выражениями работает и для записи. После INSERT автоинкрементный идентификатор новой строки доступен через $mysqli->insert_id; после INSERT/UPDATE/DELETE свойство $mysqli->affected_rows показывает количество изменённых строк:

<?php
$name  = "Ada Lovelace";
$email = "[email protected]";

$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email);   // two strings
$stmt->execute();

echo "Inserted user #" . $mysqli->insert_id;
$stmt->close();
?>

Полную картину операций CRUD смотрите в PHP MySQL Insert Data и PHP MySQL Update Data.

Обработка ошибок

Если запрос завершается неудачей, query() возвращает false, а подробности доступны на объекте соединения. Чтение $mysqli->error после неудачного вызова позволяет узнать, что пошло не так:

<?php
if (!$mysqli->query("SELECT * FROM no_such_table")) {
    echo "Query failed (" . $mysqli->errno . "): " . $mysqli->error;
}
?>

В процессе разработки можно заставить MySQLi автоматически выбрасывать исключения с помощью mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) — это поведение по умолчанию начиная с PHP 8.1. Дополнительно: PHP connect_error и PHP connect_errno.

MySQLi vs. PDO — что выбрать?

Оба варианта являются безопасными и современными способами работы с базой данных. Коротко о главном:

  • MySQLi работает только с MySQL/MariaDB. Он предоставляет некоторые специфичные для MySQL возможности (например, асинхронные запросы), которых нет в PDO.
  • PDO (PHP Data Objects) поддерживает десятки баз данных через единый API, поэтому переход с MySQL на PostgreSQL означает лишь смену строки подключения, а не переработку запросов. Он также поддерживает именованные заполнители (:name), которые легче читать.

Если вы точно знаете, что будете работать только с MySQL, MySQLi вполне подойдёт. Если важна переносимость, предпочтите PDO. В любом случае всегда используйте подготовленные выражения.

Резюме

  • MySQLi — стандартное расширение для работы с MySQL/MariaDB в PHP, доступное как в объектно-ориентированном, так и в процедурном стиле.
  • Создайте соединение с помощью new mysqli(...), проверьте connect_error и задайте кодировку.
  • Используйте query() + fetch_assoc() для чтения данных и перебора результатов.
  • Используйте подготовленные выражения (prepare()bind_param()execute()) для всего, что связано с пользовательским вводом, чтобы защититься от SQL-инъекций.
  • Проверяйте $mysqli->error / $mysqli->errno при сбое запроса и предпочитайте PDO, если требуется переносимость между СУБД.

Практика

Практика
Какие важные возможности предоставляет PHP MySQLi?
Какие важные возможности предоставляет PHP MySQLi?
Was this page helpful?