Введение: та самая ошибка, от которой чешутся руки закрыть браузер
Если вы когда-нибудь писали на PHP запрос к MySQL и вдруг видели в браузере что-то вроде:
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in /var/www/site/index.php on line 15
...то вы знаете это чувство. Вроде бы всё правильно: подключились, запрос написали, а PHP орёт на вас красным. Особенно обидно, когда код работает на локальном сервере, но на хостинге — нет. Или наоборот.
Эта ошибка — одна из самых популярных на Stack Overflow. Тысячи разработчиков (и мы в их числе) бились головой о клавиатуру, пытаясь понять: «Почему параметр 1 ожидает resource, а получает boolean?»
В этой статье мы не просто разберём причину, а пройдём полный путь: от воспроизведения ошибки до её исправления. А заодно посмотрим, почему старые функции mysql_* давно пора заменить на современные PDO или MySQLi. Поехали!
Как выглядит проблема на практике
Давайте смоделируем ситуацию. У вас есть таблица users, и вы хотите вывести всех пользователей. Код написан по старинке:
$link = mysql_connect('localhost', 'user', 'password');
mysql_select_db('test');
$result = mysql_query("SELECT * FROM users");
while ($row = mysql_fetch_array($result)) {
echo $row['name'] . '<br>';
}
Вроде бы классика. Но если таблица users не существует, или в SQL синтаксическая ошибка, то mysql_query() вернёт не resource, а false. И тогда mysql_fetch_array() получает boolean вместо resource — отсюда и ошибка.
Чаще всего проблема кроется именно в неудачном выполнении запроса. Но давайте разберём все возможные причины по порядку.
Причина №1: SQL-запрос вернул false
Это самая распространённая ситуация. mysql_query() возвращает false, если запрос не удался. Например:
- Таблица не существует
- Неверное имя поля
- Синтаксическая ошибка в SQL
- Проблемы с правами доступа
Как проверить? Просто добавьте проверку после запроса:
$result = mysql_query("SELECT * FROM non_existent_table");
if (!$result) {
die('Ошибка запроса: ' . mysql_error());
}
while ($row = mysql_fetch_array($result)) {
// ...
}
Это сразу покажет, в чём дело. mysql_error() выдаст текст ошибки, например: "Table 'test.non_existent_table' doesn't exist".
Причина №2: Потеря соединения с БД
Иногда соединение обрывается (например, из-за тайм-аута или перезагрузки MySQL). Тогда mysql_query() тоже вернёт false. Решение — всегда проверять соединение:
$link = mysql_connect('localhost', 'user', 'password');
if (!$link) {
die('Не удалось подключиться: ' . mysql_error());
}
Но даже это не панацея. Лучше использовать функции, которые умеют автоматически переподключаться — например, MySQLi.
Причина №3: Вы путаете функции mysql_* и mysqli_*
Ещё один частый случай. Вы можете случайно смешивать две разные библиотеки. Например, подключиться через mysqli_connect(), а запрос делать через mysql_query(). Это не сработает: mysql_query() ожидает resource от mysql_connect(), а не от mysqli_connect().
Вот пример путаницы:
// Подключение через MySQLi
$link = mysqli_connect('localhost', 'user', 'password', 'test');
// А запрос через старую mysql_*
$result = mysql_query("SELECT * FROM users"); // Ошибка!
while ($row = mysql_fetch_array($result)) {
echo $row['name'];
}
Решение — придерживаться одной библиотеки. Либо всё через mysql_* (но не рекомендуется), либо через mysqli_*.
«А зачем вообще нужен resource?» — спросите вы
В PHP resource — это специальный тип, который указывает на внешний ресурс (например, подключение к БД или результат запроса). Старые функции mysql_* работают именно с resource. А современные — с объектами (PDO или MySQLi).
Если вы используете mysql_query(), то при успехе получаете resource. Если ошибка — получаете false. PHP не умеет обрабатывать false как resource, отсюда и предупреждение.
Как исправить раз и навсегда: переходим на PDO
Лучший способ забыть об этой ошибке — перестать использовать функции mysql_*. Они объявлены устаревшими ещё в PHP 5.5 и удалены в PHP 7.0. Если вы пишете на PHP 7 или 8, код с mysql_fetch_array() вообще не заработает.
Вот пример того же самого кода, но на PDO (PHP Data Objects):
try {
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("SELECT * FROM users");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'] . '<br>';
}
} catch (PDOException $e) {
echo 'Ошибка соединения или запроса: ' . $e->getMessage();
}
Преимущества:
- Нет ошибок с resource — всё через объекты
- Автоматическая обработка ошибок через исключения
- Поддержка разных СУБД (не только MySQL)
- Безопасность при использовании подготовленных запросов
Альтернатива: MySQLi (MySQL improved)
Если вы не хотите переходить на PDO, используйте MySQLi. Он тоже решает проблему с resource, но остаётся в мире MySQL:
$mysqli = new mysqli('localhost', 'user', 'password', 'test');
if ($mysqli->connect_error) {
die('Ошибка подключения: ' . $mysqli->connect_error);
}
$result = $mysqli->query("SELECT * FROM users");
if ($result) {
while ($row = $result->fetch_assoc()) {
echo $row['name'] . '<br>';
}
} else {
echo 'Ошибка запроса: ' . $mysqli->error;
}
Обратите внимание: $result->fetch_assoc() — это метод объекта, а не функция. И никаких resource.