Подробное руководство по функции mysqli_sqlstate в PHP
Узнайте, как mysqli_sqlstate() возвращает коды SQLSTATE в PHP, чем отличается от mysqli_errno() и как использовать её в режиме исключений.
При работе с MySQL в PHP через расширение mysqli вам нужен надёжный способ выяснить, почему запрос завершился неудачно. Функция mysqli_sqlstate() возвращает код ошибки SQLSTATE для последней выполненной операции MySQL — стандартизированный переносимый код, указывающий категорию ошибки.
В этом руководстве объясняется, что такое SQLSTATE, чем mysqli_sqlstate() отличается от MySQL-специфичной mysqli_errno(), какие коды встречаются чаще всего и как правильно использовать эту функцию (в том числе в современном режиме PHP с исключениями).
Что такое SQLSTATE?
SQLSTATE — это пятисимвольный код ошибки, определённый стандартом ANSI/ISO SQL. Поскольку он является частью стандарта, а не изобретением MySQL, один и тот же код означает примерно одно и то же в разных СУБД, что делает его более переносимым, чем vendor-специфичные номера ошибок.
Пять символов разделены на две части:
- Первые два символа обозначают класс ошибки. Например, класс
00означает успех,01— предупреждение, а42— нарушение синтаксиса или правил доступа. - Последние три символа — это подкласс, который уточняет проблему.
Таким образом, 42S02 («базовая таблица или представление не найдено») относится к классу 42 (нарушение синтаксиса/доступа) с подклассом S02.
Синтаксис
mysqli_sqlstate(mysqli $connection): stringmysqli_sqlstate() принимает один аргумент — объект соединения, возвращаемый mysqli_connect(), — и возвращает строку:
- Пустую, но заполненную нулями строку
"00000", если последняя операция выполнена успешно. - Пятисимвольный код, например
"42S02", при возникновении ошибки.
В объектно-ориентированном стиле это метод
$connection->sqlstate.
SQLSTATE против mysqli_errno: что выбрать?
Эти две функции отвечают на разные вопросы, и зачастую нужны обе:
| Функция | Возвращает | Характер |
|---|---|---|
mysqli_sqlstate() | 5-символьную строку, например "42S02" | Стандарт ANSI/ISO — переносим между СУБД |
mysqli_errno() | Целое число, например 1146 | MySQL-специфичный — более детальный, но не переносимый |
mysqli_error() | Читаемое сообщение | Описательный текст для логирования/отладки |
Практическое правило: используйте ветвление на основе mysqli_sqlstate(), когда хотите, чтобы код пережил смену СУБД; обращайтесь к mysqli_errno(), когда нужно различить MySQL-специфичные ситуации. mysqli_error() используйте для сообщения в лог.
Полный пример
Код ниже подключается к базе данных, выполняет запрос к несуществующей таблице и выводит все три диагностических значения:
<?php
$connection = mysqli_connect('localhost', 'user', 'password', 'mydatabase');
if (!$connection) {
die('Connection failed: ' . mysqli_connect_error());
}
$sql = "SELECT * FROM table_that_does_not_exist";
if (mysqli_query($connection, $sql)) {
echo "Query executed successfully.";
} else {
echo "SQLSTATE: " . mysqli_sqlstate($connection) . "\n";
echo "Errno: " . mysqli_errno($connection) . "\n";
echo "Message: " . mysqli_error($connection) . "\n";
}
// Typical output:
// SQLSTATE: 42S02
// Errno: 1146
// Message: Table 'mydatabase.table_that_does_not_exist' doesn't existОбратите внимание, как переносимый SQLSTATE (42S02) и MySQL-специфичный номер ошибки (1146) описывают одну и ту же проблему с разной степенью детализации.
Распространённые коды SQLSTATE
Это коды, с которыми вы, скорее всего, будете сталкиваться в повседневной работе с PHP и MySQL:
| SQLSTATE | Значение |
|---|---|
00000 | Успех — ошибки нет |
23000 | Нарушение ограничения целостности (например, дублирующийся ключ, ошибка внешнего ключа) |
42000 | Синтаксическая ошибка или нарушение правил доступа |
42S02 | Базовая таблица или представление не найдено |
42S22 | Столбец не найден |
HY000 | Общая ошибка (используется, когда нет более конкретного кода) |
08S01 | Сбой связи / разрыв соединения |
Ветвление на основе этих кодов позволяет реагировать осмысленно — например, обрабатывать ошибку 23000 с дублирующимся ключом как «запись уже существует», а не как критическую ошибку:
<?php
$sql = "INSERT INTO users (email) VALUES ('[email protected]')";
if (!mysqli_query($connection, $sql)) {
if (mysqli_sqlstate($connection) === '23000') {
echo "That email address is already registered.";
} else {
echo "Unexpected database error: " . mysqli_error($connection);
}
}Использование в режиме исключений
Современный PHP (8.1+) включает отчёты об ошибках MySQL по умолчанию, поэтому неудачный запрос выбрасывает исключение mysqli_sql_exception вместо возврата false. В этом режиме SQLSTATE читается из метода getSqlState() исключения, а не через вызов mysqli_sqlstate() после факта:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$connection = mysqli_connect('localhost', 'user', 'password', 'mydatabase');
mysqli_query($connection, "SELECT * FROM missing_table");
} catch (mysqli_sql_exception $e) {
echo "SQLSTATE: " . $e->getSqlState() . "\n"; // e.g. 42S02
echo "Code: " . $e->getCode() . "\n"; // e.g. 1146
echo "Message: " . $e->getMessage();
}Если вы вызываете
mysqli_sqlstate()непосредственно после перехваченного исключения, это тоже работает — но внутри блокаtry/catchчтение кода из объекта исключения чище и не требует повторного обращения к состоянию соединения.
Подводные камни
- Функция отражает только последнюю операцию. Каждый новый запрос перезаписывает предыдущий SQLSTATE. Читайте его сразу после нужного вызова — до выполнения любых других операций на том же соединении.
"00000"означает успех, а не ошибку. Не воспринимайте непустой возврат как сбой; успешная операция возвращает строку из нулей, а не"".- У неудачного соединения нет SQLSTATE. Если сам
mysqli_connect()завершился неудачно, объекта соединения для запроса не существует — используйтеmysqli_connect_error()для диагностики проблем подключения.
Заключение
mysqli_sqlstate() возвращает переносимый, основанный на стандартах код SQLSTATE для последней операции MySQL, дополняя MySQL-специфичный mysqli_errno() и читаемый mysqli_error(). Используйте ветвление по SQLSTATE, когда хотите получить независимую от СУБД обработку ошибок; переходите к getSqlState() исключения в режиме исключений PHP по умолчанию; и всегда читайте код сразу после описываемой им операции.