next_result
В этой статье рассматривается функция mysqli_next_result() в PHP, которая используется для подготовки следующего результата mysqli_multi_query().
Когда вы отправляете несколько SQL-операторов в MySQL за один вызов с помощью mysqli_multi_query(), сервер возвращает их по одному набору результатов за раз. mysqli_next_result() — это функция, которая переводит вас с текущего набора результатов на следующий, позволяя перебрать их все. В этой статье объясняется, что возвращает функция, какие параметры принимает, какие встречаются подводные камни и как использовать её в процедурном и объектно-ориентированном стилях MySQLi.
Что делает mysqli_next_result()
mysqli_next_result() подготавливает следующий набор результатов от предыдущего вызова mysqli_multi_query() и делает его доступным для функций получения данных, таких как mysqli_store_result() или mysqli_fetch_assoc(). Внутри MySQL буферизует все наборы результатов многострочного запроса; эта функция продвигает внутренний указатель на один шаг вперёд.
Важно: один вызов mysqli_next_result() перемещает вас вперёд только на один шаг. Чтобы обработать каждый оператор, вы вызываете функцию в цикле до тех пор, пока результаты не закончатся.
Синтаксис
// Procedural style
mysqli_next_result(mysqli $mysql): bool
// Object-oriented style
$mysqli->next_result(): boolПараметры
$mysql(только процедурный стиль) — объект соединения, возвращённыйmysqli_connect(). В ООП-стиле это объект, на котором вызывается метод.
Возвращаемое значение
Возвращает boolean:
true— следующий набор результатов успешно подготовлен (или больше результатов нет и ошибки не возникло).false— в следующем операторе произошла ошибка, либо предыдущий запрос не имел буферизованных результатов для перехода.
Чтобы отличить «больше результатов нет» от «следующий оператор завершился с ошибкой», используйте mysqli_more_results(): если mysqli_more_results() возвращает true, а mysqli_next_result() — false, значит следующий оператор вызвал ошибку.
Как использовать mysqli_next_result() (процедурный стиль)
Выполните пакет с помощью mysqli_multi_query(), обработайте первый набор результатов, затем выполняйте цикл, пока есть ещё результаты, продвигаясь с помощью mysqli_next_result() на каждом шаге:
<?php
$mysqli = mysqli_connect("localhost", "username", "password", "database");
if (!$mysqli) {
die("Connection failed: " . mysqli_connect_error());
}
$query = "SELECT name FROM users LIMIT 1;";
$query .= "SELECT title FROM posts LIMIT 1;";
if (mysqli_multi_query($mysqli, $query)) {
do {
// mysqli_store_result() returns false for statements that
// produce no rows (INSERT, UPDATE, DELETE), so guard with if.
if ($result = mysqli_store_result($mysqli)) {
while ($row = mysqli_fetch_assoc($result)) {
print_r($row);
}
mysqli_free_result($result);
}
// Stop when there are no more results; otherwise advance.
} while (mysqli_more_results($mysqli) && mysqli_next_result($mysqli));
} else {
echo "Multi-query failed: " . mysqli_error($mysqli);
}
mysqli_close($mysqli);
?>Условие do...while — ключевая идея: mysqli_more_results() проверяет, существует ли ещё один набор, а mysqli_next_result() фактически переходит к нему. Поскольку && вычисляется с коротким замыканием, mysqli_next_result() вызывается только когда следующий результат действительно существует, что позволяет избежать предупреждения, которое иначе возникло бы при вызове функции после последнего набора.
Объектно-ориентированный стиль
Та же логика с ООП API выглядит немного чище:
<?php
$mysqli = new mysqli("localhost", "username", "password", "database");
if ($mysqli->connect_errno) {
die("Connection failed: " . $mysqli->connect_error);
}
$sql = "SELECT name FROM users LIMIT 1;";
$sql .= "SELECT title FROM posts LIMIT 1;";
if ($mysqli->multi_query($sql)) {
do {
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_assoc()) {
print_r($row);
}
$result->free();
}
} while ($mysqli->more_results() && $mysqli->next_result());
}
$mysqli->close();
?>Типичные подводные камни
- Всегда очищайте очередь. Если вы выполняете другой запрос, пока наборы результатов от предыдущего
mysqli_multi_query()ещё не обработаны, MySQLi выдаёт ошибку "Commands out of sync". Выполняйте цикл сmysqli_next_result()до тех пор, покаmysqli_more_results()не вернётfalse, прежде чем выдавать новый запрос. - Забывать
mysqli_store_result()для операторов не-SELECT. Такие операторы, какINSERT, не возвращают набор результатов, поэтомуmysqli_store_result()вернётfalse— это ожидаемое поведение, а не ошибка. Конструкцияif ($result = ...)справляется с этим. - Многострочный запрос представляет риск SQL-инъекций. Передавайте в
mysqli_multi_query()только доверенный SQL, контролируемый на стороне сервера. Никогда не добавляйте пользовательский ввод в многострочную строку; используйте подготовленные операторы для пользовательских данных.
Заключение
mysqli_next_result() — это функция, которая позволяет перебрать все наборы результатов, возвращённые одним вызовом mysqli_multi_query(). Используемая вместе с mysqli_more_results() внутри цикла do...while, она позволяет безопасно обрабатывать вывод каждого оператора и предотвращает рассинхронизацию соединения. Подробнее о связанном процессе читайте в mysqli_multi_query() и mysqli_fetch_assoc().