Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11468 глав6256 карточек справочника
Дерево руководства

Глава 128 · После таблиц и чтения результатов X DevAPI

MySQL X DevAPI: предупреждения, ID вставки и несколько результатов

Проверить сохранённую цену, понять сообщения импорта, связать созданную запись по ID и дочитать все части серверного отчёта.

Показать человеку действительный итог операции

Кнопка «сохранить» должна сообщать, что действительно произошло: какая цена записана, какая строка импорта пропущена и какой заказ создан. А экран отчёта должен получить все его части, даже если первая пуста. В этой главе учимся читать не только данные, но и квитанцию операции.

Что возвращает операция
  1. SQL или Table-команда с нужными данными
  2. MySQL выполняет действие и формирует диагностику
  3. PHP получает Result / RowResult / DocResult / SqlStatementResult
  4. Экран показывает readback, причины и следующий шаг

Результат похож на квитанцию с несколькими полями: данные, ID, число изменений и сообщения. Аналогия ограничена: разные классы содержат разные возможности, а серверная операция может завершиться исключением до выдачи квитанции. BaseResult — только общий договор о двух методах диагностики; он не превращает все ответы в один тип строк.

ИсходЧто проверитьЧто показать человеку
Исключение во время executeСоединение, запрос и допустимость входа; при необходимости rollbackДействие не завершено, понятная причина
Успешный ответ с сообщениямиgetWarningsCount, getWarnings и сохранённые данныеЧто сделано и какая часть требует внимания
Успешный ответ без сообщенийСтроки/ID/число изменений по смыслу задачиДействительный результат, включая «не найдено»
CALL с несколькими наборамиВсе части и конец последовательностиКаждый раздел отчёта, затем новое действие

В примерах используется подготовленный Session и учебная схема. Таблицы, строки результата и отправка SQL объяснены раньше; текущие методы сначала разобраны коротко, затем включены в самостоятельные программы.

Код архивов создаёт только свои случайно названные таблицы, коллекции и процедуры. result.html показывает полезный итог, result.json сохраняет исходные строки, типы и сообщения, metrics.json — выполненные проверки и очистку. Учебная учётная запись должна иметь права на эти объекты своей схемы; глобальные настройки сервера не меняются.

Предупреждения сервера не заменяют проверку формы. Ввод и проверка формы объясняют, как не принять строку 12x за количество, а исключения — как отделить отказ выполнения от обычного пустого результата.

Увидеть округление цены после успешного сохранения

Поставщик прислал цену 12.345, а в каталоге предусмотрено два знака после точки. Команда успешно завершается, но в таблице оказывается 12.35. Научимся показывать человеку сохранённое значение и объяснять, почему оно отличается от входного, вместо безусловного сообщения «всё сохранено».

Путь данных
  1. Вход: строка цены 12.345
  2. DECIMAL(6,2) хранит два знака
  3. Result содержит сообщение 1265
  4. Повторное SELECT показывает 12.35

Разобрать новую операцию

$receipt — квитанция выполненной команды. getWarnings() без аргументов возвращает массив сообщений, getWarningsCount() — их число. У каждого сообщения есть message (текст), code (код причины) и level (уровень). Квитанция не содержит новую цену: для неё нужен отдельный SELECT. DECIMAL(6,2) допускает всего шесть десятичных цифр, из них две после точки; PHP-строка с точкой передаёт десятичное значение без предварительного округления через float.

$receipt = $prices->update()->set('price', '12.345')->where('id = 1')->execute();
$warnings = $receipt->getWarnings();
$count = $receipt->getWarningsCount();

Результат на исходных данных

НаблюдениеРезультат
Отправлено12.345
Сохранено12.35
Сообщений о первом сохранении1
Код первого сообщения1265
Сообщений о точной цене0
Цена после второго сохранения12.35
Самостоятельная программа и архив
Увидеть округление цены после успешного сохраненияСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

function warningDetails(mysql_xdevapi\BaseResult $result): array {
    $details = [];
    foreach ($result->getWarnings() as $warning) {
        $details[] = ['message'=>$warning->message, 'level'=>$warning->level,
            'code'=>$warning->code, 'type'=>get_debug_type($warning)];
    }
    return $details;
}

    $name = x142OwnTable($session,$schema,$owned,'rounding',
        '(id INT PRIMARY KEY, price DECIMAL(6,2) NOT NULL) ENGINE=InnoDB');
    $prices = $schema->getTable($name);
    $prices->insert(['id','price'])->values([1,'12.00'])->execute();
    $mode = $session->sql('SELECT @@session.sql_mode AS sql_mode')->execute()->fetchOne();
    $sent = '12.345';
    $receipt = $prices->update()->set('price',$sent)->where('id = 1')->execute();
    $warnings = warningDetails($receipt);
    $warningCount = $receipt->getWarningsCount();
    $saved = $prices->select(['price'])->where('id = 1')->execute()->fetchOne();

    // Подтверждённая точность: отправляем уже согласованную цену с двумя знаками.
    $exactReceipt = $prices->update()->set('price','12.35')->where('id = 1')->execute();
    $exactWarnings = warningDetails($exactReceipt);
    $exactCount = $exactReceipt->getWarningsCount();
    $exactSaved = $prices->select(['price'])->where('id = 1')->execute()->fetchOne();
    $rows = [['Отправлено',$sent],['Сохранено',$saved['price']],
        ['Сообщений о первом сохранении',$warningCount],['Код первого сообщения',$warnings[0]['code'] ?? null],
        ['Сообщений о точной цене',$exactCount],['Цена после второго сохранения',$exactSaved['price']]];
    $checks = ['decimal_rounding_visible'=>$sent !== $saved['price'] && $saved['price'] === '12.35',
        'rounding_warning_observed'=>$warningCount === 1 && count($warnings) === 1 && $warnings[0]['code'] === 1265,
        'exact_input_has_no_warning'=>$exactCount === 0 && $exactWarnings === [] && $exactSaved['price'] === '12.35',
        'receipt_is_base_result'=>$receipt instanceof mysql_xdevapi\BaseResult];
    $observations = ['sent'=>$sent,'saved'=>$saved,'warnings'=>$warnings,'exact_warnings'=>$exactWarnings,
        'exact_saved'=>$exactSaved,'receipt_type'=>get_debug_type($receipt),'saved_type'=>get_debug_type($saved['price']),
        'sql_mode'=>$mode['sql_mode']];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-warning-rounding-receipt', 'Увидеть округление цены после успешного сохранения', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Отправлено — 12.345
Сохранено — 12.35
Сообщений о первом сохранении — 1
Код первого сообщения — 1265
Сообщений о точной цене — 0
Цена после второго сохранения — 12.35

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

Округление дробной части при записи DECIMAL даёт диагностическое сообщение даже при строгом SQL-режиме; выход за диапазон — другая ситуация и может завершиться исключением. Сообщение уровня Note тоже находится в списке диагностики. Не ищите ошибку только по английскому тексту: сохраняйте code, level и исходный message. Цена в JSON остаётся строкой. В рабочей форме правило точности задают до записи: отклонить лишние знаки либо явно согласовать округление; предупреждение сервера не заменяет это решение.

Разработчик сохранял AVG(price) в DECIMAL с меньшим числом дробных знаков и получил сообщения о потере точности. В нашем сценарии та же потребность раскрыта на одной цене: вход, сохранённое значение и диагностика показаны рядом. Обсуждение: Data truncated при сохранении средней цены.

Измените требование

Поставщик прислал 12.3, а затем 12.345. Как ответить ему так, чтобы он понимал, какое значение будет сохранено?

Разбор следующего шага

12.3 можно показать как цену 12.30 без изменения величины. Для 12.345 до записи сообщите, что каталог хранит два дробных знака, и получите согласованное значение или отклоните строку. После выполнения сверяйте сохранённое значение; не подавляйте сообщения изменением глобального SQL-режима.

Не принять число 12 из испорченного количества 12x

В файле поставщика количество оказалось строкой 12x. CAST возвращает число 12, но это ещё не означает, что вход корректен. Сравним результат преобразования и диагностику, а затем увидим два нормальных случая без предупреждений: найденный товар и отсутствие товара по ID.

Путь данных
  1. Поставщик → raw_qty = 12x
  2. CAST читает числовое начало → 12
  3. RowResult и SQL сообщают 1292
  4. Чистый DocResult: [] предупреждений, даже если товар не найден

Разобрать новую операцию

CAST — операция MySQL, которая преобразует значение в указанный SQL-тип. UNSIGNED здесь означает неотрицательное целое, AS quantity даёт имя столбцу ответа. Вопросительный знак — место значения, bind передаёт строку отдельно от SQL. fetchOne читает строку, getWarnings — диагностику той же команды. TableSelect возвращает RowResult, SQL возвращает SqlStatementResult, поиск документов — DocResult; у всех есть общий интерфейс диагностики.

$result = $session->sql('SELECT CAST(? AS UNSIGNED) AS quantity')->bind('12x')->execute();
$row = $result->fetchOne();
$warnings = $result->getWarnings();

Результат на исходных данных

НаблюдениеРезультат
Входное количество12x
Результат TableSelect12
Предупреждений TableSelect1
Предупреждений SQL1
Корректная строка 12: предупреждения0
Найденный документЛампа
Предупреждений DocResult0
Отсутствующий товар: документов0
Отсутствующий товар: предупреждения0
Самостоятельная программа и архив
Не принять число 12 из испорченного количества 12xСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

function warningDetails(mysql_xdevapi\BaseResult $result): array {
    $details = [];
    foreach ($result->getWarnings() as $warning) {
        $details[] = ['message'=>$warning->message, 'level'=>$warning->level,
            'code'=>$warning->code, 'type'=>get_debug_type($warning)];
    }
    return $details;
}

    $name = x142OwnTable($session,$schema,$owned,'conversion',
        '(id INT PRIMARY KEY, raw_qty VARCHAR(20) NOT NULL) ENGINE=InnoDB');
    $incoming = $schema->getTable($name);
    $incoming->insert(['id','raw_qty'])->values([1,'12x'])->execute();
    $rowResult = $incoming->select(['CAST(raw_qty AS UNSIGNED) AS quantity'])->execute();
    $rowValues = $rowResult->fetchAll();
    $rowWarnings = warningDetails($rowResult);
    $rowCount = $rowResult->getWarningsCount();
    $sqlResult = $session->sql('SELECT CAST(? AS UNSIGNED) AS quantity')->bind('12x')->execute();
    $sqlValues = $sqlResult->fetchAll();
    $sqlWarnings = warningDetails($sqlResult);
    $sqlCount = $sqlResult->getWarningsCount();
    $validResult = $session->sql('SELECT CAST(? AS UNSIGNED) AS quantity')->bind('12')->execute();
    $validValues = $validResult->fetchAll();
    $validWarnings = warningDetails($validResult);

    $collectionName = x142OwnCollection($schema,$owned,'read_documents');
    $products = $schema->getCollection($collectionName);
    $products->add(['_id'=>'LED','name'=>'Лампа','stock'=>3])->execute();
    $docResult = $products->find('_id = :id')->bind(['id'=>'LED'])->execute();
    $documents = $docResult->fetchAll();
    $docWarnings = warningDetails($docResult);
    $docCount = $docResult->getWarningsCount();
    $missing = $products->find('_id = :id')->bind(['id'=>'MISSING'])->execute();
    $missingDocuments = $missing->fetchAll();
    $missingWarnings = warningDetails($missing);
    $rows = [['Входное количество','12x'],['Результат TableSelect',(int)$rowValues[0]['quantity']],
        ['Предупреждений TableSelect',$rowCount],['Предупреждений SQL',$sqlCount],
        ['Корректная строка 12: предупреждения',$validResult->getWarningsCount()],
        ['Найденный документ',$documents[0]['name']],['Предупреждений DocResult',$docCount],
        ['Отсутствующий товар: документов',count($missingDocuments)],['Отсутствующий товар: предупреждения',$missing->getWarningsCount()]];
    $checks = ['conversion_keeps_numeric_prefix'=>(int)$rowValues[0]['quantity'] === 12 && (int)$sqlValues[0]['quantity'] === 12,
        'conversion_warns_both_apis'=>$rowCount === 1 && $sqlCount === 1 && $rowWarnings[0]['code'] === 1292 && $sqlWarnings[0]['code'] === 1292,
        'valid_conversion_clean'=>(int)$validValues[0]['quantity'] === 12 && $validResult->getWarningsCount() === 0 && $validWarnings === [],
        'document_read_clean'=>$documents[0]['name'] === 'Лампа' && $docWarnings === [] && $docCount === 0,
        'empty_is_not_warning'=>$missingDocuments === [] && $missingWarnings === [] && $missing->getWarningsCount() === 0];
    $observations = ['row_values'=>$rowValues,'row_warnings'=>$rowWarnings,'sql_values'=>$sqlValues,'sql_warnings'=>$sqlWarnings,
        'valid_values'=>$validValues,'valid_warnings'=>$validWarnings,'documents'=>$documents,'doc_warnings'=>$docWarnings,
        'missing_documents'=>$missingDocuments,'missing_warnings'=>$missingWarnings,
        'types'=>[get_debug_type($rowResult),get_debug_type($sqlResult),get_debug_type($docResult)]];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-warning-read-conversion', 'Не принять число 12 из испорченного количества 12x', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Входное количество — 12x
Результат TableSelect — 12
Предупреждений TableSelect — 1
Предупреждений SQL — 1
Корректная строка 12: предупреждения — 0
Найденный документ — Лампа
Предупреждений DocResult — 0
Отсутствующий товар: документов — 0
Отсутствующий товар: предупреждения — 0

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

Получившееся число нельзя использовать как доказательство правильного ввода: до CAST нужна проверка формата по правилам поля. Нулевое число предупреждений также не гарантирует, что товар найден: отдельно проверяйте пустую выборку. PHP Manual содержит ошибочное отрицание getWarningsCount в примере DocResult; правильный смысл: 0 — сообщений нет, положительное число — прочитайте сообщения. Ошибка доступа или синтаксиса обычно прервёт execute исключением и не должна маскироваться пустым списком.

Измените требование

Что должен показать экран по ID MISSING: ошибку базы, сообщение «товар не найден» или товар с остатком 0?

Разбор следующего шага

Запрос успешно выполнился, но документов нет: покажите «товар не найден». Остаток 0 относится к существующему товару и не заменяет отсутствие документа. Сбой сервера обрабатывается отдельной веткой исключения.

Отчитаться о принятой и пропущенной позиции импорта

В каталоге уже есть LED с остатком 10. Импорт содержит LED с числом 99 и новый CABLE с остатком 3. Требование этого режима: добавлять только новые артикулы и явно сообщать о пропусках. Увидим, почему успешный INSERT IGNORE нельзя выдавать за успешное сохранение всех строк файла.

Путь данных
  1. Каталог: LED = 10
  2. Импорт: LED = 99; CABLE = 3
  3. IGNORE пропускает дубль, сохраняет CABLE
  4. Квитанция: принято 1; код 1062; readback LED остаётся 10

Разобрать новую операцию

PRIMARY KEY запрещает повтор SKU. Без IGNORE конфликт прерывает INSERT исключением; IGNORE разрешает MySQL преобразовать некоторые ошибки в предупреждения и продолжить. getAffectedItemsCount даёт число принятых строк, getWarnings — причины диагностируемых пропусков. Это разные показатели. Два вызова bind соответствуют двум знакам ? слева направо; имя таблицы берётся из собственной лаборатории, не из формы.

$receipt = $session->sql('INSERT IGNORE INTO '.$qualified.' (sku,stock) VALUES (?,?)')
    ->bind('LED')->bind(99)->execute();
$accepted = $receipt->getAffectedItemsCount();
$warnings = $receipt->getWarnings();

Результат на исходных данных

НаблюдениеРезультат
Строгая вставка дубля отклоненада
Новых строк принято1
Сообщений INSERT IGNORE1
Код сообщения1062
LED: прежний остаток10
CABLE: новый остаток3
Самостоятельная программа и архив
Отчитаться о принятой и пропущенной позиции импортаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

function warningDetails(mysql_xdevapi\BaseResult $result): array {
    $details = [];
    foreach ($result->getWarnings() as $warning) {
        $details[] = ['message'=>$warning->message, 'level'=>$warning->level,
            'code'=>$warning->code, 'type'=>get_debug_type($warning)];
    }
    return $details;
}

    $name = x142OwnTable($session,$schema,$owned,'import',
        '(sku VARCHAR(20) PRIMARY KEY, stock INT NOT NULL) ENGINE=InnoDB');
    $products = $schema->getTable($name);
    $products->insert(['sku','stock'])->values(['LED',10])->execute();
    $qualified = x142Qualified($schema,$name);
    $duplicate = x142Failure(static fn() => $session->sql('INSERT INTO '.$qualified.' (sku,stock) VALUES (?,?)')
        ->bind('LED')->bind(99)->execute());
    $receipt = $session->sql('INSERT IGNORE INTO '.$qualified.' (sku,stock) VALUES (?,?),(?,?)')
        ->bind('LED')->bind(99)->bind('CABLE')->bind(3)->execute();
    $warnings = warningDetails($receipt);
    $warningCount = $receipt->getWarningsCount();
    $acceptedCount = $receipt->getAffectedItemsCount();
    $saved = $products->select(['sku','stock'])->orderby('sku ASC')->execute()->fetchAll();
    $bySku = array_column($saved,'stock','sku');
    $duplicateCodes = array_column($duplicate ?? [],'code');
    $rows = [['Строгая вставка дубля отклонена',$duplicate !== null],['Новых строк принято',$acceptedCount],
        ['Сообщений INSERT IGNORE',$warningCount],['Код сообщения',$warnings[0]['code'] ?? null],
        ['LED: прежний остаток',(int)$bySku['LED']],['CABLE: новый остаток',(int)$bySku['CABLE']]];
    $checks = ['duplicate_is_error'=>$duplicate !== null && in_array(1062,$duplicateCodes,true),
        'one_new_row_accepted'=>$acceptedCount === 1 && count($saved) === 2,
        'ignored_duplicate_reported'=>$warningCount === 1 && count($warnings) === 1 && $warnings[0]['code'] === 1062,
        'old_stock_not_overwritten'=>(int)$bySku['LED'] === 10 && (int)$bySku['CABLE'] === 3];
    $observations = ['strict_duplicate_exception'=>$duplicate,'ignored_warnings'=>$warnings,
        'saved_rows'=>$saved,'result_type'=>get_debug_type($receipt),'accepted_count'=>$acceptedCount];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-warning-import-policy', 'Отчитаться о принятой и пропущенной позиции импорта', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Строгая вставка дубля отклонена — да
Новых строк принято — 1
Сообщений INSERT IGNORE — 1
Код сообщения — 1062
LED: прежний остаток — 10
CABLE: новый остаток — 3

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

IGNORE может затронуть не только дубликаты, но и преобразования значений. Поэтому он допустим лишь при явной политике импорта, а не как универсальное лечение ошибки. Для атомарного импорта используйте обычные INSERT в транзакции и rollback при отказе. Число принятых строк не перечисляет отвергнутые позиции: промышленному импорту нужны собственные номера строк/артикулы и журнал проверки. Сообщение сервера может содержать данные, поэтому в публичном интерфейсе показывают понятную причину, а подробности сохраняют в доступном оператору журнале.

Вопрос об импорте: INSERT IGNORE перестал прерываться на дублях, но автору нужен понятный список пропусков. Сам счётчик принятых строк этого не объясняет; наша программа сочетает квитанцию, сообщения и фактические SKU в таблице. Обсуждение: Как пропускать дубли и получать сведения о пропусках.

Измените требование

Если обновление должно заменить остаток LED на 99, достаточно ли оставить INSERT IGNORE?

Разбор следующего шага

Нет: его смысл в этом примере — сохранить прежний LED. Для изменения выберите отдельный UPDATE или явно спроектированный UPSERT, определите правила конфликта и защиту от устаревших данных. Отчёт должен отдельно считать добавления, изменения и пропуски.

Связать созданный заказ с его заметкой по настоящему ID

После создания заказа нужно открыть именно его страницу и привязать заметку сотрудника. Не угадываем следующий номер и не ищем MAX(id): получаем ID из квитанции своего INSERT. Затем отдельно создаём второй заказ через SQL и убеждаемся, что две квитанции ведут к разным строкам.

Путь данных
  1. TableInsert создаёт заказ LED
  2. Result → getAutoIncrementValue → $id
  3. Заметка получает order_id = $id
  4. SELECT по $id возвращает именно LED

Разобрать новую операцию

AUTO_INCREMENT — серверный механизм выдачи значения столбцу id. Столбец не указан в INSERT, поэтому его заполняет MySQL. getAutoIncrementValue() вызывается без аргументов у Result этой вставки. Для SqlStatementResult от SQL INSERT соответствующий метод — getLastInsertId(). Во внешнем ключе order_id сохраняется значение ID, а не номер строки PHP-массива. Транзакция связывает создание заказа и заметки в одну операцию.

$receipt = $orders->insert(['sku'])->values(['LED'])->execute();
$id = $receipt->getAutoIncrementValue();
$created = $orders->select(['id', 'sku'])->where('id = :id')->bind(['id' => $id])->execute()->fetchOne();

Результат на исходных данных

НаблюдениеРезультат
Заказ из квитанции TableInsertLED
Заметка относится к этому заказуда
Текст заметкиПерезвонить покупателю
Заказ из квитанции SQLCABLE
Получены разные IDда
Самостоятельная программа и архив
Связать созданный заказ с его заметкой по настоящему IDСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

    $name = x142OwnTable($session,$schema,$owned,'receipt_orders',
        '(id INT PRIMARY KEY AUTO_INCREMENT, sku VARCHAR(20) NOT NULL) ENGINE=InnoDB');
    $qualified = x142Qualified($schema,$name);
    $noteName = x142OwnTable($session,$schema,$owned,'receipt_notes',
        '(id INT PRIMARY KEY, order_id INT NOT NULL, message VARCHAR(80) NOT NULL, FOREIGN KEY (order_id) REFERENCES '.$qualified.' (id)) ENGINE=InnoDB');
    $orders = $schema->getTable($name);
    $notes = $schema->getTable($noteName);
    $session->startTransaction();
    try {
        $receipt = $orders->insert(['sku'])->values(['LED'])->execute();
        $id = $receipt->getAutoIncrementValue();
        $notes->insert(['id','order_id','message'])->values([1,$id,'Перезвонить покупателю'])->execute();
        $session->commit();
    } catch (Throwable $error) {$session->rollback(); throw $error;}
    $sqlReceipt = $session->sql('INSERT INTO '.$qualified.' (sku) VALUES (?)')->bind('CABLE')->execute();
    $sqlId = $sqlReceipt->getLastInsertId();
    $first = $orders->select(['id','sku'])->where('id = :id')->bind(['id'=>$id])->execute()->fetchOne();
    $second = $orders->select(['id','sku'])->where('id = :id')->bind(['id'=>$sqlId])->execute()->fetchOne();
    $note = $notes->select(['order_id','message'])->where('id = 1')->execute()->fetchOne();
    $rows = [['Заказ из квитанции TableInsert',$first['sku']],['Заметка относится к этому заказу',(string)$note['order_id'] === (string)$id],
        ['Текст заметки',$note['message']],['Заказ из квитанции SQL',$second['sku']],['Получены разные ID',(string)$id !== (string)$sqlId]];
    $checks = ['table_receipt_matches_row'=>$first['sku'] === 'LED' && (string)$first['id'] === (string)$id,
        'child_uses_returned_id'=>(string)$note['order_id'] === (string)$id && $note['message'] === 'Перезвонить покупателю',
        'sql_receipt_matches_row'=>$second['sku'] === 'CABLE' && (string)$second['id'] === (string)$sqlId,
        'receipts_distinct'=>(string)$id !== (string)$sqlId];
    $observations = ['table_insert_id'=>$id,'sql_insert_id'=>$sqlId,'id_types'=>[get_debug_type($id),get_debug_type($sqlId)],
        'table_row'=>$first,'sql_row'=>$second,'note'=>$note,'result_types'=>[get_debug_type($receipt),get_debug_type($sqlReceipt)]];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-result-auto-increment-receipt', 'Связать созданный заказ с его заметкой по настоящему ID', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Заказ из квитанции TableInsert — LED
Заметка относится к этому заказу — да
Текст заметки — Перезвонить покупателю
Заказ из квитанции SQL — CABLE
Получены разные ID — да

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

PHP Manual показывает возвращаемый int. В выбранном исходнике PECL очень большое значение, начиная с ZEND_LONG_MAX, возвращается десятичной строкой; не превращайте ID во float и не требуйте непрерывной последовательности. В этой программе вставляется по одному заказу; квитанция не является массивом всех ID пакетной вставки. Generated document IDs у коллекций относятся к другому механизму. Реальные ID и их типы сохранены в result.json, а проверки доказывают связь с конкретными прочитанными строками.

Измените требование

Какой URL показать покупателю после вставки и что делать, если запись заметки не удалась?

Разбор следующего шага

В маршрут заказа передайте ID из его квитанции; при чтении дополнительно проверьте права покупателя на этот заказ. Если заметка обязательна и INSERT заметки завершился ошибкой, rollback отменит создание заказа в этой транзакции. Выданный номер может оставить пробел в последовательности — это не повод искать или переиспользовать его.

Не потерять сводку после пустого списка отмен

Экран отправки показывает отменённые заказы и отдельную сводку готовых. Сегодня отмен нет, но готовы две отправки на 2700 копеек. Процедура возвращает два ответа. Если остановиться на первом пустом массиве, оператор ошибочно останется без полезной сводки.

Путь данных
  1. CALL отчёта
  2. Часть 1: отмены → пусто
  3. nextResult true → часть 2: готово 2, сумма 2700
  4. nextResult false → следующий запрос разрешён

Разобрать новую операцию

Процедура — именованный набор SQL-действий на сервере; CALL запускает её. Два SELECT внутри дают два набора ответа, каждый со своими строками и полями. do выполняет тело хотя бы один раз, затем проверяет условие продолжения. В выбранном расширении nextResult() возвращает bool и переключает тот же $result на следующую часть. Это не fetchOne: он меняет набор, а не берёт ещё одну строку текущего набора. И это не повторный execute: процедура запускается один раз.

$result = $session->sql('CALL '.$qualifiedProcedure.'()')->execute();
do {
    $rows = $result->getColumnsCount() > 0 ? $result->fetchAll() : [];
    // Обработайте текущую часть, даже если $rows пуст.
} while ($result->nextResult() === true);

Результат на исходных данных

НаблюдениеРезультат
Наборов показал nextResult2
Отменённых отправлений0
Готовых отправлений2
Сумма готовых, коп.2700
Переход после пустого наборада
Последний переходнет
Следующий запрос соединения1
Самостоятельная программа и архив
Не потерять сводку после пустого списка отменСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

    $name = x142OwnTable($session,$schema,$owned,'dispatch',
        '(id INT PRIMARY KEY, state VARCHAR(20) NOT NULL, amount_cents INT NOT NULL) ENGINE=InnoDB');
    $dispatch = $schema->getTable($name);
    $dispatch->insert(['id','state','amount_cents'])->values([1,'ready',1200])
        ->values([2,'ready',1500])->values([3,'done',800])->execute();
    $q = x142Qualified($schema,$name);
    $procedure = x142OwnProcedure($session,$schema,$owned,'dispatch_report',
        'BEGIN SELECT id,amount_cents FROM '.$q.' WHERE state = \'cancelled\' ORDER BY id; '
        .'SELECT COUNT(*) AS ready_count, SUM(amount_cents) AS ready_cents FROM '.$q.' WHERE state = \'ready\'; END');
    $result = $session->sql('CALL '.x142Qualified($schema,$procedure).'()')->execute();
    if ($result === false) {throw new RuntimeException('Отчёт не выполнен.');}
    $parts = [];
    do {
        if (count($parts) >= 8) {throw new RuntimeException('Неожиданно много частей отчёта.');}
        $count = $result->getColumnsCount();
        $part = ['type'=>get_debug_type($result),'has_data'=>$result->hasData(),
            'columns'=>$result->getColumnNames(),'rows'=>$count > 0 ? $result->fetchAll() : []];
        $next = $result->nextResult();
        $part['next'] = $next;
        $part['next_type'] = get_debug_type($next);
        $parts[] = $part;
    } while ($next === true);
    $after = $session->sql('SELECT 1 AS ready')->execute()->fetchOne();
    $summary = $parts[1]['rows'][0] ?? [];
    $rows = [['Наборов показал nextResult',count($parts)],['Отменённых отправлений',count($parts[0]['rows'])],
        ['Готовых отправлений',(int)($summary['ready_count'] ?? -1)],['Сумма готовых, коп.',(int)($summary['ready_cents'] ?? -1)],
        ['Переход после пустого набора',$parts[0]['next']],['Последний переход',$parts[count($parts)-1]['next']],
        ['Следующий запрос соединения',(int)$after['ready']]];
    $checks = ['empty_first_not_end'=>count($parts) === 2 && $parts[0]['rows'] === [] && $parts[0]['next'] === true,
        'summary_not_lost'=>(int)$summary['ready_count'] === 2 && (int)$summary['ready_cents'] === 2700,
        'next_is_boolean'=>$parts[0]['next_type'] === 'bool' && $parts[1]['next_type'] === 'bool' && $parts[1]['next'] === false,
        'session_ready_after_drain'=>$after === ['ready'=>1]];
    $observations = ['parts'=>$parts,'after'=>$after,'summary'=>$summary,
        'explanation'=>'Synchronous nextResult consumes final completion without exposing it as a separate result object in this runtime.'];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-procedure-result-sequence', 'Не потерять сводку после пустого списка отмен', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Наборов показал nextResult — 2
Отменённых отправлений — 0
Готовых отправлений — 2
Сумма готовых, коп. — 2700
Переход после пустого набора — да
Последний переход — нет
Следующий запрос соединения — 1

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

PHP Manual обещает Result в сигнатуре nextResult, но PECL 8.0.30 и реальный запуск возвращают true/false. Не присваивайте $result = $result->nextResult(). Пустая первая часть CALL в этом окружении сообщает 0 столбцов и hasData=false, но следующая часть существует. Этот синхронный путь поглощает служебное завершение CALL при переходе к концу; отдельным третьим объектом оно не показано. Другой способ чтения в следующем уроке показывает его явно. Ограничение 8 — предохранитель для известной короткой процедуры, а не замена чтения до конца. SUM сохраняется как исходная строка в JSON; приведение к int здесь ограничено маленькой суммой копеек, большие DECIMAL требуют точной десятичной обработки.

В обсуждении используется MySQLi, но практическая проблема относится к незавершённому чтению ответа перед новой командой. Мы не переносим чужой API: пишем самостоятельный X DevAPI-пример, дочитываем ответ и проверяем следующий запрос. Обсуждение: Почему после процедуры возникает Commands out of sync.

Измените требование

В очереди появился отменённый заказ. Должен ли экран прекращать чтение после получения его строки? А если готовых отправлений больше нет?

Разбор следующего шага

Нет: после списка отмен всё равно читается сводка. Когда ready нет, COUNT даст 0, SUM без COALESCE даст NULL; это надо явно отобразить как отсутствие суммы или заранее договорённый ноль. Не заканчивайте последовательность по пустым строкам — конец определяет nextResult.

Отправить отчёт и получить все его части через SqlStatement

Счёт содержит две лампы по 1200 копеек и кабель за 800. Отчёт должен вернуть позиции и итог 3200. Теперь разделим отправку команды и получение ответа: подготовим подписи экрана локально, затем прочитаем обе части и служебное завершение, прежде чем выполнять следующий SQL.

Путь данных
  1. execute ASYNC | BUFFERED → отправлено true
  2. PHP готовит подписи без нового SQL
  3. getResult → позиции; getNextResult → сумма
  4. hasMoreResults → служебное завершение → false

Разобрать новую операцию

:: обращается к константе класса. Знак | объединяет флаги: EXECUTE_ASYNC отделяет отправку от чтения ответа, BUFFERED выбирает буферизацию. True от execute в этом режиме означает успешную отправку, а не готовые строки. getResult() получает первый ответ; getNextResult() получает следующий; hasMoreResults() проверяется после чтения текущего. Эти методы вызываются у $statement. Методы fetchAll и getColumnsCount вызываются у полученного $current.

$statement = $session->sql('CALL '.$qualifiedProcedure.'()');
$sent = $statement->execute(mysql_xdevapi\SqlStatement::EXECUTE_ASYNC | mysql_xdevapi\SqlStatement::BUFFERED);
$first = $statement->getResult();
// Прочитайте $first, затем проверяйте hasMoreResults() перед getNextResult().

Результат на исходных данных

НаблюдениеРезультат
Отправка принятада
Строк в разделе «Позиции счёта»2
Первая позицияЛампа
Итого, коп.3200
Наборов прочитано через statement3
Строк в служебном завершении0
Остались результатынет
Следующий запрос соединения1
Самостоятельная программа и архив
Отправить отчёт и получить все его части через SqlStatementСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';

$config = x142Config();
$session = mysql_xdevapi\getSession($config['uri']);
$schema = null;
$owned = [];
$removed = [];
$rows = $checks = $observations = [];
try {
    $schema = $session->getSchema($config['schema']);
    if (!$schema->existsInDatabase()) {
        throw new RuntimeException('Учебная схема не существует: подготовьте её отдельно.');
    }
    $runtime = ['php'=>PHP_VERSION, 'extension'=>phpversion('mysql_xdevapi'),
        'server_version'=>$session->getServerVersion(), 'schema'=>$config['schema'],
        'host'=>$config['host'], 'port'=>$config['port']];

    $name = x142OwnTable($session,$schema,$owned,'invoice_lines',
        '(id INT PRIMARY KEY, title VARCHAR(40) NOT NULL, qty INT NOT NULL, unit_cents INT NOT NULL) ENGINE=InnoDB');
    $lines = $schema->getTable($name);
    $lines->insert(['id','title','qty','unit_cents'])->values([1,'Лампа',2,1200])->values([2,'Кабель',1,800])->execute();
    $q = x142Qualified($schema,$name);
    $procedure = x142OwnProcedure($session,$schema,$owned,'invoice_report',
        'BEGIN SELECT title,qty,unit_cents FROM '.$q.' ORDER BY id; '
        .'SELECT SUM(qty * unit_cents) AS total_cents FROM '.$q.'; END');
    $statement = $session->sql('CALL '.x142Qualified($schema,$procedure).'()');
    $sent = $statement->execute(mysql_xdevapi\SqlStatement::EXECUTE_ASYNC | mysql_xdevapi\SqlStatement::BUFFERED);
    if ($sent !== true) {throw new RuntimeException('Команда отчёта не отправлена.');}
    // Только локальная работа: вторую SQL-команду в этот Session ещё не отправляем.
    $headings = ['Позиции счёта','Итого','Завершение CALL'];
    $current = $statement->getResult();
    $parts = [];
    while ($current !== false && $current !== null) {
        if (count($parts) >= 8) {throw new RuntimeException('Неожиданно много частей отчёта.');}
        $count = $current->getColumnsCount();
        $part = ['type'=>get_debug_type($current),'has_data'=>$current->hasData(),
            'columns'=>$current->getColumnNames(),'rows'=>$count > 0 ? $current->fetchAll() : []];
        $more = $statement->hasMoreResults();
        $part['more'] = $more;
        $parts[] = $part;
        if (!$more) {break;}
        $current = $statement->getNextResult();
    }
    $after = $session->sql('SELECT 1 AS ready')->execute()->fetchOne();
    $total = $parts[1]['rows'][0]['total_cents'] ?? null;
    $rows = [['Отправка принята',$sent],['Строк в разделе «'.$headings[0].'»',count($parts[0]['rows'])],
        ['Первая позиция',$parts[0]['rows'][0]['title']],['Итого, коп.',(int)$total],
        ['Наборов прочитано через statement',count($parts)],['Строк в служебном завершении',count($parts[2]['rows'])],
        ['Остались результаты',$parts[count($parts)-1]['more']],['Следующий запрос соединения',(int)$after['ready']]];
    $checks = ['async_send_acknowledged'=>$sent === true,
        'details_read'=>count($parts[0]['rows']) === 2 && $parts[0]['rows'][0]['title'] === 'Лампа' && (int)$parts[0]['rows'][0]['qty'] === 2,
        'invoice_total_read'=>(int)$total === 3200,
        'service_completion_consumed'=>count($parts) === 3 && $parts[2]['rows'] === [] && $parts[2]['more'] === false,
        'next_query_succeeds'=>$after === ['ready'=>1]];
    $observations = ['sent'=>$sent,'sent_type'=>get_debug_type($sent),'headings'=>$headings,'parts'=>$parts,
        'after'=>$after,'total_raw'=>$total,'total_php_type'=>get_debug_type($total)];

} finally {
    try {
        if ($schema instanceof mysql_xdevapi\Schema) {
            $removed = x142Cleanup($schema, $owned);
        }
    } finally {
        $session->close();
    }
}

x142Report('mysql142-x-statement-result-access', 'Отправить отчёт и получить все его части через SqlStatement', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Отправка принята — да
Строк в разделе «Позиции счёта» — 2
Первая позиция — Лампа
Итого, коп. — 3200
Наборов прочитано через statement — 3
Строк в служебном завершении — 0
Остались результаты — нет
Следующий запрос соединения — 1

CLI-программа создаёт собственные учебные объекты, выполняет команды, читает реальные данные и удаляет созданные объекты. Откройте result.html, а исходные значения, типы и сообщения посмотрите в result.json. Это не HTTP-обработчик.

Таблица фактического запуска · Исходные результаты и диагностика в JSON.

Границы и типичные ошибки

Не смешивайте этот способ с nextResult() на тех же ответах: у одной последовательности должен быть один способ чтения. В выбранном окружении statement-путь возвращает ещё и пустой служебный результат CALL: получились три объекта для двух SELECT. getResult может ждать ответ; это не обещание полностью неблокирующего выполнения, параллельных запросов в одном Session или ускорения. Не вызывайте hasMoreResults до отправки команды. BUFFERED не отменяет необходимость ограничивать большие отчёты SQL-фильтрами. Исходный DECIMAL итог сохранён строкой; int в экране допустим лишь для малого проверенного диапазона этого примера.

Измените требование

Нужно показать первый раздел раньше второго. Можно ли после чтения позиций отправить в тот же Session новый запрос к покупателю?

Разбор следующего шага

Сначала дочитайте текущую последовательность, включая завершение. Для данных покупателя добавьте нужный запрос в продуманный отчёт либо запросите его после завершения CALL. Если действительно нужна независимая параллельная работа, понадобится другое соединение и отдельная оценка согласованности данных; одного ASYNC-флага недостаточно.

Найти нужную часть квитанции

ИнструментЗачем нужен
BaseResultПозволяет одной функции отчёта принимать разные квитанции результата.
BaseResult::getWarningsЗадаёт общий способ прочитать сообщения сервера о выполненной операции.
BaseResult::getWarningsCountЗадаёт общий счётчик диагностики сервера.
WarningХранит одно сообщение сервера, которое помогает объяснить результат операции.
Result::getWarningsЧитает диагностику квитанции Result, например после TableUpdate.
Result::getWarningsCountВозвращает счётчик диагностики Result без аргументов.
RowResult::getWarningsПолучает сообщения операции, вернувшей RowResult.
RowResult::getWarningsCountВозвращает счётчик без аргументов.
DocResult::getWarningsЧитает диагностику поиска, возвращающего DocResult, без аргументов.
DocResult::getWarningsCountВозвращает счётчик без аргументов.
SqlStatementResult::getWarningsПолучает диагностику результата Session::sql.
SqlStatementResult::getWarningsCountВозвращает счётчик без аргументов.
Result::getAutoIncrementValueДаёт идентификатор, выданный сервером для вставки, без дополнительного запроса MAX(id).
SqlStatementResult::nextResultПереходит к следующему набору ответа одной команды, например CALL процедуры с несколькими SELECT.
SqlStatement::getResultПолучает ответ уже отправленной SQL-команды.
SqlStatement::getNextResultПолучает следующую часть ответа у SqlStatement, когда hasMoreResults сообщает её наличие.
SqlStatement::hasMoreResultsПроверяет продолжение последовательности после чтения текущей части.

Собрать понятный отчёт импорта

Следующий проект: импорт с предварительной проверкой строк, явной политикой дубликатов, квитанцией по каждой порции и ссылками на созданные записи. До записи решите, какие данные отклонять, какие преобразования разрешать и какие части операции должны быть неделимыми. Показывайте принятые, изменённые и пропущенные позиции отдельно.

Для отображения столбцов используйте метаданные и понятные заголовки отчёта. Изменения таблиц и общая транзакция объясняют согласованную запись, а запрос под нужный экран — как не выгружать всё ради небольшого результата.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

mysql_xdevapi\BaseResultПозволяет одной функции отчёта принимать разные квитанции результата.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

interface mysql_xdevapi\BaseResult { public function getWarnings(): array; public function getWarningsCount(): int; }

Позволяет одной функции отчёта принимать разные квитанции результата.

Запись, параметры и результат

interface mysql_xdevapi\BaseResult { public function getWarnings(): array; public function getWarningsCount(): int; }

Описание типа. Объекты результата и предупреждения предоставляет расширение после выполнения команды.

Общий интерфейс диагностики результата; сам по себе он не создаёт запрос и не содержит универсального метода чтения строк.

Позволяет одной функции отчёта принимать разные квитанции результата. PHP Manual называет BaseResult интерфейсом, но в кратком synopsis показывает class с двумя abstract public методами. Реальный Reflection и исходник PECL 8.0.30 подтверждают interface; доступность класса/интерфейса в Manual указана с PECL 8.0.11. Контракт содержит getWarnings(): array и getWarningsCount(): int без аргументов. Result, RowResult, DocResult и SqlStatementResult поддерживают диагностику, но читаются по-разному. new BaseResult не создаёт полезный объект: передавайте уже полученный результат команды.

Два применения

Общая функция подготовки журнала

Одинаково получаем детали округления цены и диагностику SQL-импорта. В самостоятельных программах это делает warningDetails().

function messages(mysql_xdevapi\BaseResult $receipt): array {
    $rows = [];
    foreach ($receipt->getWarnings() as $warning) {
        $rows[] = ['code' => $warning->code, 'level' => $warning->level, 'message' => $warning->message];
    }
    return $rows;
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Общий индикатор без предположения о строках

Проверка подходит и для DocResult; существование товара проверяется отдельно через чтение документа.

function hasDiagnostics(mysql_xdevapi\BaseResult $receipt): bool {
    return $receipt->getWarningsCount() > 0;
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\BaseResult::getWarningsЗадаёт общий способ прочитать сообщения сервера о выполненной операции.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

abstract public mysql_xdevapi\BaseResult::getWarnings(): array

Задаёт общий способ прочитать сообщения сервера о выполненной операции.

Запись, параметры и результат

abstract public mysql_xdevapi\BaseResult::getWarnings(): array

Метод не принимает аргументов.

Массив объектов Warning; если диагностических сообщений нет, пустой массив.

Задаёт общий способ прочитать сообщения сервера о выполненной операции. Аргументов нет; метод реализуется конкретными результатами. Каждый элемент предоставляет message, level и code. Формулировка Manual про errors не означает, что исключение SQL превращается в элемент этого массива: список предупреждений и прервавший запрос отказ нужно различать. Сохраняйте диагностику нужной квитанции, а не случайного последующего SELECT. Документационный пример использует RowResult с делением на ноль; здесь тот же контракт раскрыт на цене и импорте.

Два применения

Объяснить изменение цены

После округления читаем сообщение 1265, затем сравниваем сохранённую цену с входной.

$messages = $receipt->getWarnings();
foreach ($messages as $warning) {
    echo $warning->code, ': ', $warning->message, PHP_EOL;
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Приложить причины к отчёту импорта

Здесь $receipt — SQL-квитанция INSERT IGNORE; её дополнительный метод affected count не является частью BaseResult.

$report = ['accepted' => $receipt->getAffectedItemsCount(), 'warnings' => []];
foreach ($receipt->getWarnings() as $warning) {
    $report['warnings'][] = ['code' => $warning->code, 'message' => $warning->message];
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\BaseResult::getWarningsCountЗадаёт общий счётчик диагностики сервера.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

abstract public mysql_xdevapi\BaseResult::getWarningsCount(): int

Задаёт общий счётчик диагностики сервера.

Запись, параметры и результат

abstract public mysql_xdevapi\BaseResult::getWarningsCount(): int

Метод не принимает аргументов.

Число диагностических сообщений последней операции соответствующего результата; 0 означает отсутствие сообщений.

Задаёт общий счётчик диагностики сервера. Аргументов нет; он не равен числу строк, товаров или изменённых записей. Один проблемный расчёт может давать сообщение для каждой строки. Получите сами сообщения через getWarnings, когда нужно объяснить причину. У страниц методов Manual нет надёжно указанной начальной версии; наличие проверяется для выбранного расширения. Не приравнивайте нулевой счётчик к успешной бизнес-операции: нужной записи может не существовать.

Два применения

Показать индикатор у сохранённой цены

Уведомление ведёт к деталям и фактической цене, а не заменяет их.

$noticeCount = $receipt->getWarningsCount();
if ($noticeCount > 0) {
    echo 'Проверьте сохранённую цену: есть сообщения сервера.';
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Различить отсутствие товара и отсутствие предупреждений

У MISSING одновременно found=false и noticeCount=0: это обычная пустая выборка.

$documents = $docResult->fetchAll();
$noticeCount = $docResult->getWarningsCount();
$found = $documents !== [];

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\WarningХранит одно сообщение сервера, которое помогает объяснить результат операции.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

class mysql_xdevapi\Warning { public $message; public $level; public $code; private function __construct(); }

Хранит одно сообщение сервера, которое помогает объяснить результат операции.

Запись, параметры и результат

class mysql_xdevapi\Warning { public $message; public $level; public $code; private function __construct(); }

Описание типа. Объекты результата и предупреждения предоставляет расширение после выполнения команды.

Объект сообщения из getWarnings(): текст message, числовой уровень level и числовой код code.

Хранит одно сообщение сервера, которое помогает объяснить результат операции. PHP Manual указывает PECL mysql_xdevapi >= 8.0.11 и три публичных свойства без объявленных типов; конструктор private. Получайте объект от драйвера, а не через new Warning. В выбранном запуске message — string, level и code — int: округление DECIMAL вернуло code 1265/level 1, проблемное преобразование и дубликат — level 2. Уровень и код решают разные задачи; 1265 — причина, а 1 — категория сообщения. Сам объект не отменяет запрос и не выполняет rollback.

Два применения

Сохранить точную причину округления

Записываем все три поля; сообщение уровня Note остаётся значимой диагностикой.

foreach ($receipt->getWarnings() as $warning) {
    $diagnostic = ['code' => $warning->code, 'level' => $warning->level, 'message' => $warning->message];
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Безопасно показать сообщение оператору в HTML

Текст может содержать SKU и другие данные: вывод экранируется, а подробный журнал доступен только нужной роли.

foreach ($receipt->getWarnings() as $warning) {
    echo '<p>', htmlspecialchars($warning->message, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</p>';
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\Result::getWarningsЧитает диагностику квитанции Result, например после TableUpdate.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\Result::getWarnings(): array

Читает диагностику квитанции Result, например после TableUpdate.

Запись, параметры и результат

public mysql_xdevapi\Result::getWarnings(): array

Метод не принимает аргументов.

Массив Warning, полученных для выполненного изменения; [] при отсутствии сообщений.

Читает диагностику квитанции Result, например после TableUpdate. Аргументов нет. Warning содержит message, level и code. Официальный пример на этой странице фактически использует RowResult; это не отменяет существования метода у Result. Наша самостоятельная программа получает именно Result от записи цены. Сообщения не содержат всех новых значений столбцов — сохранённое состояние проверяется отдельным чтением.

Два применения

Цена потеряла лишний дробный знак

Сообщение объясняет изменение 12.345 → 12.35.

$receipt = $prices->update()->set('price', '12.345')->where('id = 1')->execute();
$messages = $receipt->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Точное значение по согласованной шкале

Пустой массив относится к этой записи; цену всё равно можно прочитать для ответа форме.

$receipt = $prices->update()->set('price', '12.35')->where('id = 1')->execute();
$messages = $receipt->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\Result::getWarningsCountВозвращает счётчик диагностики Result без аргументов.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\Result::getWarningsCount(): int

Возвращает счётчик диагностики Result без аргументов.

Запись, параметры и результат

public mysql_xdevapi\Result::getWarningsCount(): int

Метод не принимает аргументов.

Количество сообщений результата изменения; не количество изменённых строк.

Возвращает счётчик диагностики Result без аргументов. При необходимости объяснить причину используйте getWarnings. Число affected items — другая характеристика; изменение могло затронуть строку и одновременно вернуть сообщение. Ноль сообщений не доказывает, что пользовательская цель выполнена: запрос мог не найти нужный ID или сохранить значение, допустимое SQL, но запрещённое бизнес-правилом.

Два применения

Сохранение с заметкой о точности

Одна изменённая цена может дать одно предупреждение; это не два результата записи.

$count = $receipt->getWarningsCount();
$needsReview = $count > 0;

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Квитанция создания заказа

ID нужен для перехода к заказу, а диагностика — для объяснения выполнения; показатели не заменяют друг друга.

$receipt = $orders->insert(['sku'])->values(['LED'])->execute();
$id = $receipt->getAutoIncrementValue();
$diagnostics = $receipt->getWarningsCount();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\RowResult::getWarningsПолучает сообщения операции, вернувшей RowResult.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\RowResult::getWarnings(): array

Получает сообщения операции, вернувшей RowResult.

Запись, параметры и результат

public mysql_xdevapi\RowResult::getWarnings(): array

Метод не принимает аргументов.

Массив Warning чтения таблицы, пустой при отсутствии диагностики.

Получает сообщения операции, вернувшей RowResult. Аргументов нет. SELECT тоже может завершиться с предупреждениями: арифметика или преобразование исходного текста могут дать значение вместе с диагностикой. Официальный пример показывает деление на ноль и Warning с message/level/code. Для рабочего экрана важно сохранить и прочитанные строки, и сообщения, не считать любое полученное число корректным вводом.

Два применения

Число из испорченного поля поставщика

Количество 12 сопровождается кодом 1292 из-за исходной строки 12x.

$result = $incoming->select(['CAST(raw_qty AS UNSIGNED) AS quantity'])->execute();
$rows = $result->fetchAll();
$messages = $result->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Предупреждение при расчёте цены за единицу

Контекст для таблицы с quantity: нулевой делитель нужно обрабатывать по смыслу задачи, а не заменять результат молча. В самостоятельном уроке показан тот же путь чтения и диагностики для CAST.

$result = $lines->select(['id', 'amount_cents / quantity AS unit_cents'])->execute();
$rows = $result->fetchAll();
$messages = $result->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\RowResult::getWarningsCountВозвращает счётчик без аргументов.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\RowResult::getWarningsCount(): int

Возвращает счётчик без аргументов.

Запись, параметры и результат

public mysql_xdevapi\RowResult::getWarningsCount(): int

Метод не принимает аргументов.

Число сообщений сервера для RowResult; не число найденных строк.

Возвращает счётчик без аргументов. В официальном примере два деления на ноль дают два сообщения; это демонстрирует, что одна SQL-команда может породить несколько предупреждений. Для простого чтения без диагностики счётчик равен нулю даже при наличии строк. Число ошибок импорта не следует выводить из этого счётчика без собственного определения, что считается проблемной строкой.

Два применения

Отметить строку с подозрительным преобразованием

Требуется разбор текста 12x до принятия количества.

$result = $incoming->select(['CAST(raw_qty AS UNSIGNED) AS quantity'])->execute();
$rows = $result->fetchAll();
$requiresReview = $result->getWarningsCount() > 0;

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Посчитать позиции и диагностику отдельно

Чтение исходного текста не означает его проверки как числа: rows может быть 1, warnings — 0.

$result = $incoming->select(['id', 'raw_qty'])->execute();
$rows = $result->fetchAll();
$report = ['rows' => count($rows), 'warnings' => $result->getWarningsCount()];

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\DocResult::getWarningsЧитает диагностику поиска, возвращающего DocResult, без аргументов.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\DocResult::getWarnings(): array

Читает диагностику поиска, возвращающего DocResult, без аргументов.

Запись, параметры и результат

public mysql_xdevapi\DocResult::getWarnings(): array

Метод не принимает аргументов.

Массив Warning поиска документов; [] при отсутствии сообщений.

Читает диагностику поиска, возвращающего DocResult, без аргументов. Каждое сообщение имеет message, level и code. В PHP Manual у примера ошибочно написано отрицание getWarningsCount перед сообщением об ошибке; не воспроизводите его: ноль означает отсутствие предупреждений. Пустой список диагностики не означает наличие документа. Полученные документы и проблемы исполнения — отдельные части ответа.

Два применения

Прочитать найденный товар и его диагностику

В учебной коллекции получаем лампу и пустой список сообщений.

$result = $products->find('_id = :id')->bind(['id' => 'LED'])->execute();
$documents = $result->fetchAll();
$warnings = $result->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Корректный запрос по отсутствующему ID

Два пустых массива имеют разный смысл: товаров не найдено, сообщений сервера нет.

$result = $products->find('_id = :id')->bind(['id' => 'MISSING'])->execute();
$documents = $result->fetchAll();
$warnings = $result->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\DocResult::getWarningsCountВозвращает счётчик без аргументов.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\DocResult::getWarningsCount(): int

Возвращает счётчик без аргументов.

Запись, параметры и результат

public mysql_xdevapi\DocResult::getWarningsCount(): int

Метод не принимает аргументов.

Число диагностических сообщений поиска документов; 0 означает отсутствие сообщений.

Возвращает счётчик без аргументов. Это не число документов и не логический флаг «товар существует». Неверное отрицание в примере Manual противоречит описанию метода: ветка для диагностики должна проверять > 0. При сетевой или SQL-ошибке execute может выбросить исключение ещё до получения DocResult; такой отказ не подменяется нулём предупреждений.

Два применения

Показать индикатор у найденного товара

Для лампы foundCount=1 и warningCount=0.

$documents = $result->fetchAll();
$warningCount = $result->getWarningsCount();
$foundCount = count($documents);

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Проверить нормальный пустой поиск

Оба флага false: это отдельный исход «не найдено», без выдуманной ошибки сервера.

$result = $products->find('_id = :id')->bind(['id' => 'MISSING'])->execute();
$found = $result->fetchOne() !== null;
$hasWarnings = $result->getWarningsCount() > 0;

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\SqlStatementResult::getWarningsПолучает диагностику результата Session::sql.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatementResult::getWarnings(): array

Получает диагностику результата Session::sql.

Запись, параметры и результат

public mysql_xdevapi\SqlStatementResult::getWarnings(): array

Метод не принимает аргументов.

Массив Warning SQL-операции; [] если сообщений нет.

Получает диагностику результата Session::sql. Аргументов нет. PHP Manual помечает описание незавершённым, но задаёт массив объектов с message, level и code. Самостоятельные примеры показывают чтение с преобразованием и INSERT IGNORE: наличие строк или положительного affected count не исключает предупреждения. Читайте диагностику именно своей квитанции, прежде чем формировать итог пользователю.

Два применения

Объяснить число после SQL CAST

Числовое начало прочитано, но формат входной строки не признан корректным.

$result = $session->sql('SELECT CAST(? AS UNSIGNED) AS quantity')->bind('12x')->execute();
$quantity = $result->fetchOne()['quantity'];
$warnings = $result->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Показать причину пропуска импорта

Код 1062 объясняет конфликт ключа; прежний остаток сохраняется.

$receipt = $session->sql('INSERT IGNORE INTO '.$qualified.' (sku,stock) VALUES (?,?)')
    ->bind('LED')->bind(99)->execute();
$warnings = $receipt->getWarnings();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\SqlStatementResult::getWarningsCountВозвращает счётчик без аргументов.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatementResult::getWarningsCount(): int

Возвращает счётчик без аргументов.

Запись, параметры и результат

public mysql_xdevapi\SqlStatementResult::getWarningsCount(): int

Метод не принимает аргументов.

Количество диагностических сообщений SQL-операции.

Возвращает счётчик без аргументов. На странице Manual заголовок указывает getWarningsCount, а строка сигнатуры ошибочно пишет getWarningCounts; реальный метод выбранного расширения — getWarningsCount. URL страницы также использует singular getwarningcount, это не имя PHP-метода. Счётчик не сообщает, какие строки пропущены: для этого нужны сами сообщения и собственный отчёт импорта.

Два применения

Разделить успешную запись и полноту импорта

Принята одна новая строка, но есть предупреждение о дубле другой строки.

$accepted = $receipt->getAffectedItemsCount();
$noticeCount = $receipt->getWarningsCount();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Проверить точное числовое чтение

Для исходной строки 12 результат 12 без предупреждений; это отличается от строки 12x.

$result = $session->sql('SELECT CAST(? AS UNSIGNED) AS quantity')->bind('12')->execute();
$row = $result->fetchOne();
$noticeCount = $result->getWarningsCount();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\Result::getAutoIncrementValueДаёт идентификатор, выданный сервером для вставки, без дополнительного запроса MAX(id).

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\Result::getAutoIncrementValue(): int

Даёт идентификатор, выданный сервером для вставки, без дополнительного запроса MAX(id).

Запись, параметры и результат

public mysql_xdevapi\Result::getAutoIncrementValue(): int

Метод не принимает аргументов.

AUTO_INCREMENT ID, сохранённый в квитанции вставки. Manual показывает int; выбранный исходник возвращает строку для значений от ZEND_LONG_MAX и false при отсутствии execution state.

Даёт идентификатор, выданный сервером для вставки, без дополнительного запроса MAX(id). Аргументов нет. Рассматриваем вставку одной строки в таблицу с AUTO_INCREMENT. Manual называет значение last insert id; это данные конкретной квитанции, а не обещание получить все ID пакетного INSERT. Не вычисляйте ID по текущему числу строк и не подменяйте его generated IDs документов. В большом диапазоне сохраняйте десятичную строку без float-преобразования.

Два применения

Открыть созданный заказ

Readback подтверждает, что ID ведёт к LED, а не к чужой последней записи.

$receipt = $orders->insert(['sku'])->values(['LED'])->execute();
$id = $receipt->getAutoIncrementValue();
$created = $orders->select(['id', 'sku'])->where('id = :id')->bind(['id' => $id])->execute()->fetchOne();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Связать заметку с заказом

Обе записи помещены в одну транзакцию в полном примере; внешний ключ проверяет ссылку.

$id = $receipt->getAutoIncrementValue();
$notes->insert(['id', 'order_id', 'message'])
    ->values([1, $id, 'Перезвонить покупателю'])->execute();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Диагностика дополняет фактический результат: прочитанную цену, принятые позиции или созданную запись по её ID. Чтение строк таблицы не подменяется проверкой предупреждений.

mysql_xdevapi\SqlStatementResult::nextResultПереходит к следующему набору ответа одной команды, например CALL процедуры с несколькими SELECT.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatementResult::nextResult(): mysql_xdevapi\Result // запись PHP Manual

Переходит к следующему набору ответа одной команды, например CALL процедуры с несколькими SELECT.

Запись, параметры и результат

public mysql_xdevapi\SqlStatementResult::nextResult(): mysql_xdevapi\Result // запись PHP Manual

Метод не принимает аргументов.

В исходнике и реальном запуске PECL 8.0.30 — bool: true переключает текущий объект на следующий набор, false означает конец.

Переходит к следующему набору ответа одной команды, например CALL процедуры с несколькими SELECT. Аргументов нет. PHP Manual содержит незавершённую страницу и обещает следующий Result, но это противоречит проверенному поведению: объект остаётся тем же, возвращается признак перехода. Не путайте переход между наборами и чтение строк через fetchOne. Пустой набор не является концом последовательности. На синхронном пути служебное завершение CALL не показано отдельным объектом; его чтение завершает последовательность.

Два применения

Продолжить после пустого списка

Даже когда отмен нет, можно получить сводку готовых отправлений. Остаток последовательности всё равно дочитывается полным циклом.

$firstRows = $result->getColumnsCount() > 0 ? $result->fetchAll() : [];
if ($result->nextResult() === true) {
    $summaryRows = $result->fetchAll();
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Пройти все части отчёта

После конца соединение используется для следующего запроса; полный пример дополнительно ограничивает число частей.

do {
    $rows = $result->getColumnsCount() > 0 ? $result->fetchAll() : [];
    // Сохраните текущую часть отчёта.
} while ($result->nextResult() === true);

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Выберите один способ чтения одной команды. Переходы внутри SqlStatementResult и последовательное получение объектов через SqlStatement разобраны отдельно. Строки и признаки SQL-результата.

mysql_xdevapi\SqlStatement::getResultПолучает ответ уже отправленной SQL-команды.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatement::getResult(): mysql_xdevapi\Result // запись PHP Manual

Получает ответ уже отправленной SQL-команды.

Запись, параметры и результат

public mysql_xdevapi\SqlStatement::getResult(): mysql_xdevapi\Result // запись PHP Manual

Метод не принимает аргументов.

В проверенном режиме после ASYNC-отправки возвращает SqlStatementResult для чтения первой части; исходник также допускает false, поэтому код проверяет ответ.

Получает ответ уже отправленной SQL-команды. Аргументов в документированном вызове нет. Страница PHP Manual содержит только сигнатуру и не объясняет порядок действий; выбранный исходник и запуск показывают путь execute(ASYNC | BUFFERED) → getResult. GetResult не отправляет новый SELECT и не возвращает массив строк. Нужные fetchAll/getWarnings вызываются у полученного объекта. Начало чтения может ждать данных сервера; отдельная отправка не делает весь процесс автоматически неблокирующим.

Два применения

Получить позиции счёта после отправки

GetResult получает первую часть единственного CALL. В полном файле ответ проверяется и последовательность читается до конца.

$sent = $statement->execute(mysql_xdevapi\SqlStatement::EXECUTE_ASYNC | mysql_xdevapi\SqlStatement::BUFFERED);
if ($sent !== true) { throw new RuntimeException('Отправка не подтверждена.'); }
$result = $statement->getResult();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Подготовить подписи до чтения ответа

Фрагмент продолжает уже выполненную ASYNC-отправку: локальная подготовка не требует второго SQL на занятом соединении.

$headings = ['Позиции счёта', 'Итого'];
$result = $statement->getResult();
$rows = $result->getColumnsCount() > 0 ? $result->fetchAll() : [];

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Выберите один способ чтения одной команды. Переходы внутри SqlStatementResult и последовательное получение объектов через SqlStatement разобраны отдельно. Строки и признаки SQL-результата.

mysql_xdevapi\SqlStatement::getNextResultПолучает следующую часть ответа у SqlStatement, когда hasMoreResults сообщает её наличие.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatement::getNextResult(): mysql_xdevapi\Result // запись PHP Manual

Получает следующую часть ответа у SqlStatement, когда hasMoreResults сообщает её наличие.

Запись, параметры и результат

public mysql_xdevapi\SqlStatement::getNextResult(): mysql_xdevapi\Result // запись PHP Manual

Метод не принимает аргументов.

В проверенной последовательности возвращает следующий SqlStatementResult; защитный код допускает false/null вместо объекта.

Получает следующую часть ответа у SqlStatement, когда hasMoreResults сообщает её наличие. Аргументов в документированном вызове нет. Официальная страница не содержит полноценного описания, поэтому рабочий порядок подтверждён выбранным расширением. В исходнике getResult/getNextResult используют одну функцию чтения; имя метода не означает повторное выполнение команды. Не вызывайте одновременно nextResult у полученного результата для этой же последовательности.

Два применения

Из позиций перейти к сумме

Следующий объект содержит сводку, а не ещё одну строку позиций.

$lineRows = $current->fetchAll();
if ($statement->hasMoreResults()) {
    $current = $statement->getNextResult();
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Прочитать служебное завершение

После чтения первого ответа цикл получает и оставшийся пустой служебный ответ; полный пример контролирует число итераций.

while ($statement->hasMoreResults()) {
    $current = $statement->getNextResult();
    if ($current === false || $current === null) { break; }
    $rows = $current->getColumnsCount() > 0 ? $current->fetchAll() : [];
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Выберите один способ чтения одной команды. Переходы внутри SqlStatementResult и последовательное получение объектов через SqlStatement разобраны отдельно. Строки и признаки SQL-результата.

mysql_xdevapi\SqlStatement::hasMoreResultsПроверяет продолжение последовательности после чтения текущей части.

Типы PECL mysql_xdevapi >= 8.0.11; отдельные страницы методов не указывают начальную версию. Учебное расширение 8.0.30. · mysql_xdevapi

public mysql_xdevapi\SqlStatement::hasMoreResults(): bool

Проверяет продолжение последовательности после чтения текущей части.

Запись, параметры и результат

public mysql_xdevapi\SqlStatement::hasMoreResults(): bool

Метод не принимает аргументов.

True — у отправленной команды есть ещё результат; false — дальнейшие результаты не ожидаются по состоянию этого statement.

Проверяет продолжение последовательности после чтения текущей части. Аргументов нет. Документация кратко говорит о наличии объектов результата; речь не о количестве строк в текущей таблице. Вызывайте метод у выполненного SqlStatement, в показанном пути после getResult. Сам он не читает строки и не завершает следующий набор. False после полного чтения позволяет перейти к новой команде Session.

Два применения

Не пропустить итог счёта

Текущие строки уже прочитаны; проверка относится к следующему набору.

$more = $statement->hasMoreResults();
if ($more) {
    $next = $statement->getNextResult();
}

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Убедиться в завершении перед новым SQL

Контрольный запрос подтверждает, что соединение пригодно для следующего действия.

// Цикл getNextResult уже прочитал все части.
if ($statement->hasMoreResults()) {
    throw new RuntimeException('Отчёт ещё не дочитан.');
}
$ready = $session->sql('SELECT 1 AS ready')->execute()->fetchOne();

Контекстный фрагмент: подключение, таблица или текущий ответ уже подготовлены. Самостоятельная программа с исходными данными, чтением результата и очисткой.

Выберите один способ чтения одной команды. Переходы внутри SqlStatementResult и последовательное получение объектов через SqlStatement разобраны отдельно. Строки и признаки SQL-результата.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.