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

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

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

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

Глава 138 · После классов, первой Session и чтения результатов

MySQL X DevAPI: Statement внутри драйвера и публичный путь к результатам

Исследовать доступный Statement без обхода конструктора и выбрать проверенный публичный маршрут к строкам, нескольким ответам и ошибкам.

Как выбрать настоящий объект команды

Вы ищете способ получить результат SQL-запроса и попадаете на класс Statement с методами getResult и getNextResult. Кажется, достаточно создать такой объект. Но в установленном расширении конструктор закрыт, а команды приложения создаются другим публичным способом. Разберёмся, что именно можно проверить, какой объект действительно возвращается и как получить нужные строки, не пытаясь подделать внутренний объект драйвера.

Два уровня, которые важно различать
  1. PHP Manual → Statement: описание внутреннего класса
  2. Reflection → наличие, константы, видимость методов; без SQL
  3. Приложение → Session::sql → SqlStatement
  4. execute → SqlStatementResult → строки или квитанция

Класс описывает тип объекта. Конструктор создаёт и инициализирует экземпляр; private ограничивает его вызов самим классом. Наличие public-метода не создаёт экземпляр автоматически. Reflection — средство прочитать метаданные уже зарегистрированного класса. Здесь new ReflectionClass создаёт объект описания, а не mysql_xdevapi\Statement и не соединение с MySQL.

В PECL 8.0.30 Statement существует и используется внутри реализации CRUD. В просмотренном matching исходнике не найден публичный способ получить его как рабочий объект приложения: внутренний create_stmt получает нативный указатель, а обычный execute выдаёт конкретный объект результата. Это не объявление класса отсутствующим или официально устаревшим. На страницах методов просто нет полноценного описания поведения. Мы сохраняем их сигнатуры и отдельно показываем проверенный публичный путь.

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

Что нужноКаким объектом пользоватьсяКакой результат получить
Проверить доступный контрактReflectionClass над зарегистрированным StatementПризнаки, константы и видимость; без запроса
Подготовить SQLSession::sqlSqlStatement с bind/execute
Прочитать обычный SQL-ответSqlStatementResult после executeСтроки, столбцы, предупреждения или квитанцию
Получить части отложенного SQL-ответаSqlStatement после ASYNC executegetResult, далее getNextResult с проверкой hasMoreResults
Перейти между наборами обычного CALLSqlStatementResult::nextResultbool-переход того же результата в проверенном профиле

Ни один прямой вызов getResult/getNextResult/hasMoreResults у Statement в этой главе не объявлен проверенным прикладным сценарием. Новая самостоятельная программа безопасно читает метаданные. Для запросов, нескольких наборов и callback приведены точные ссылки на уже выполненные программы, а не повторные демонстрации с выдуманным Statement.

Три небольшие проверки перед переносом кода

Перед переносом обработчика нужно понять, зарегистрирован ли нужный класс. Проверка не должна запускать пользовательский автозагрузчик, который может создать совсем другой PHP-класс с тем же именем.

$name = 'mysql_xdevapi\\Statement';
$present = class_exists($name, false);
var_dump($present); // В профиле 8.0.30: bool(true).

Переменная $name содержит полное имя с пространством имён. Второй аргумент false отключает автозагрузку: проверяем уже имеющуюся запись. true означает, что класс существует; это ещё не разрешение создавать его через new и не доказательство выполненного SQL.

Проверить границу создания объекта

$name = 'mysql_xdevapi\\Statement';
if (class_exists($name, false)) {
    $info = new ReflectionClass($name);
    var_dump($info->getConstructor()->isPrivate()); // bool(true)
    var_dump($info->isInstantiable());              // bool(false)
}

if выполняет блок только при наличии класса. ReflectionClass принимает его имя. getConstructor возвращает описание конструктора; isPrivate отвечает о видимости, а isInstantiable — о возможности обычного создания экземпляра. В этом конкретном классе конструктор есть; универсальный инспектор должен также обработать null от getConstructor. Итог полезен для миграции: код с new Statement нужно заменить корректной фабрикой соответствующей команды, а не обходом конструктора.

Проверить метод перед выбором API

$info = new ReflectionClass('mysql_xdevapi\\Statement');
echo $info->hasMethod('execute') ? 'Есть execute' : 'Нет execute';
// Нет execute. Для SQL-команды используйте Session::sql → SqlStatement.

Название Statement не является общим интерфейсом всех команд. Нужный приложению метод execute зарегистрирован у SqlStatement, а у исследуемого Statement его нет. Полный отчёт собирает эти отдельные проверки вместе, сохраняет структуру и не вызывает методы нативного экземпляра.

Проверить доступность Statement без создания нативного объекта

Нужен отчёт для проверки совместимости: существует ли Statement, разрешено ли обычное создание, какие константы и методы зарегистрированы. Вход — метаданные текущего PHP; результат — таблица без соединения с базой. Значения 1/2 и private снимаются из настоящего расширения, а не подставляются вместо опроса.

Что делает самостоятельный файл
  1. class_exists с autoload=false
  2. ReflectionClass описывает имеющийся класс
  3. Конструктор, константы и три метода → массив наблюдений
  4. HTML/JSON → решение использовать публичный SqlStatement

Ожидаемый результат профиля 8.0.30

НаблюдениеРезультат
Statement зарегистрированда
Класс внутреннийда
Можно создать обычным newнет
Видимость конструктораprivate
EXECUTE_ASYNC1
BUFFERED2
getResult — publicда
getNextResult — publicда
hasMoreResults — publicда
У Statement есть executeнет
У SqlStatement есть public executeда
Рабочий путьSession::sql → SqlStatement → результат
Соединение с базой открывалосьнет
Самостоятельная программа и архив
Проверить доступность Statement без создания нативного объектаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$session=$schema=$config=null;
$owned=$removed=$rows=$checks=$observations=[];
$runtime=x147Runtime();
try {

    $name='mysql_xdevapi\Statement';
    if (!class_exists($name,false)) {
        throw new RuntimeException('Statement не зарегистрирован в этом PHP. Сначала проверьте загрузку и версию mysql_xdevapi.');
    }
    $class=new ReflectionClass($name);
    $constructor=$class->getConstructor();
    $constructorVisibility=$constructor===null ? 'нет' :
        ($constructor->isPrivate() ? 'private' : ($constructor->isProtected() ? 'protected' : 'public'));
    $constants=$class->getConstants();
    ksort($constants);
    $methods=[];
    foreach (['getResult','getNextResult','hasMoreResults'] as $methodName) {
        if (!$class->hasMethod($methodName)) {throw new RuntimeException('Ожидаемый метод не зарегистрирован.');}
        $method=$class->getMethod($methodName);
        $methods[$methodName]=[
            'public'=>$method->isPublic(),'static'=>$method->isStatic(),
            'required_parameters'=>$method->getNumberOfRequiredParameters(),
            'declared_parameters'=>$method->getNumberOfParameters(),
            'declared_return'=>$method->hasReturnType() ? (string)$method->getReturnType() : null,
            'declaring_class'=>$method->getDeclaringClass()->getName(),
        ];
    }
    $sqlAvailable=class_exists('mysql_xdevapi\SqlStatement',false);
    $sqlClass=$sqlAvailable ? new ReflectionClass('mysql_xdevapi\SqlStatement') : null;
    $sqlExecute=$sqlClass!==null && $sqlClass->hasMethod('execute') && $sqlClass->getMethod('execute')->isPublic();
    $publicReaders=true;
    foreach ($methods as $method) {
        $publicReaders=$publicReaders && $method['public'] && !$method['static'] && $method['required_parameters']===0;
    }
    $rows=[['Statement зарегистрирован',true],['Класс внутренний',$class->isInternal()],
        ['Можно создать обычным new',$class->isInstantiable()],['Видимость конструктора',$constructorVisibility],
        ['EXECUTE_ASYNC',$constants['EXECUTE_ASYNC']??null],['BUFFERED',$constants['BUFFERED']??null],
        ['getResult — public',$methods['getResult']['public']],
        ['getNextResult — public',$methods['getNextResult']['public']],
        ['hasMoreResults — public',$methods['hasMoreResults']['public']],
        ['У Statement есть execute',$class->hasMethod('execute')],
        ['У SqlStatement есть public execute',$sqlExecute],
        ['Рабочий путь','Session::sql → SqlStatement → результат'],
        ['Соединение с базой открывалось',false]];
    $checks=['registered_internal_class'=>$class->isInternal() && $class->getExtensionName()==='mysql_xdevapi',
        'constructor_boundary'=>$constructorVisibility==='private' && !$class->isInstantiable(),
        'constants_match'=>$constants===['BUFFERED'=>2,'EXECUTE_ASYNC'=>1],
        'three_instance_readers'=>$publicReaders && count($methods)===3,
        'public_sql_route_has_execute'=>!$class->hasMethod('execute') && $sqlExecute,
        'no_database_contact'=>$session===null && $owned===[]];
    $observations+=['class'=>$class->getName(),'extension'=>$class->getExtensionName(),
        'internal'=>$class->isInternal(),'instantiable'=>$class->isInstantiable(),
        'constructor_visibility'=>$constructorVisibility,'constants'=>$constants,'methods'=>$methods,
        'statement_has_execute'=>$class->hasMethod('execute'),'sqlstatement_has_public_execute'=>$sqlExecute,
        'native_instance_created'=>false,'native_instance_methods_called'=>false,
        'database_connection_attempted'=>false];

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

x147Report('mysql147-x-statement-contract-map', 'Проверить доступность Statement без создания нативного объекта', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Statement зарегистрирован — да
Класс внутренний — да
Можно создать обычным new — нет
Видимость конструктора — private
EXECUTE_ASYNC — 1
BUFFERED — 2
getResult — public — да
getNextResult — public — да
hasMoreResults — public — да
У Statement есть execute — нет
У SqlStatement есть public execute — да
Рабочий путь — Session::sql → SqlStatement → результат
Соединение с базой открывалось — нет

CLI-программа читает только метаданные PHP и сохраняет result.html/result.json. Нужен загруженный mysql_xdevapi; URI и MySQL-сервер не нужны. Нативные экземпляры Statement не создаются.

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

Архив содержит example.php, lab.php и README.txt. В JSON сохраняются видимость, объявленные параметры и наличие типа возврата; metrics.json — сводные проверки. Отчёт не запускает SQL, не создаёт экземпляр Statement и не выясняет готовность сервера. Если расширение отсутствует, он сообщает причину; начните с диагностики установки.

Объявленные параметры — именно метаданные регистрации, а не полный разбор аргументов внутри расширения. В этом профиле Reflection показывает ноль параметров у читателей, но общий нативный reader также содержит callback-ветвь. Поэтому по числу ноль нельзя автоматически заключать «callback не поддерживается»; его публичный путь разобран в связанной программе с фактическим результатом.

Проверьте понимание

В отчёте getResult помечен public, а класс нельзя создать обычным new. Противоречат ли эти наблюдения друг другу? Можно ли по declared_return=null объявить, что результат всегда null?

Разбор

Противоречия нет: видимость метода и способ получить правильно инициализированный экземпляр — разные условия. null в поле declared_return означает отсутствие типа в Reflection-описании, а не реальное возвращённое значение. Для полезного SQL используйте Session::sql и соответствующий результат; для Statement сохраните честную границу доступности.

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

Допустим, экран должен показать позиции счёта и итог. Рабочая команда получается из уже открытой Session. Метод sql возвращает SqlStatement; синхронный execute — результат. Следующий фрагмент показывает этот путь в контексте существующей подготовленной процедуры, а не создаёт учебную базу заново.

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

Это контекстный фрагмент для SqlStatementResult. $session и $qualifiedProcedure подготовлены в самостоятельном примере отчёта об отправлениях. Там первая часть пуста, следующая содержит 2 готовых отправления и 2700 копеек; после завершения ответов контрольный SELECT даёт 1. Нельзя присваивать $result = $result->nextResult(): в проверенном профиле nextResult возвращает bool.

Если отправка и получение разделены

$command = $session->sql('CALL ' . $qualifiedProcedure . '()');
$sent = $command->execute(mysql_xdevapi\SqlStatement::EXECUTE_ASYNC | mysql_xdevapi\SqlStatement::BUFFERED);
if ($sent !== true) { throw new RuntimeException('Команда не отправлена.'); }
$current = $command->getResult();
while ($current !== false && $current !== null) {
    $rows = $current->getColumnsCount() > 0 ? $current->fetchAll() : [];
    // Обработайте эту часть отчёта до перехода.
    if (!$command->hasMoreResults()) { break; }
    $current = $command->getNextResult();
}

Здесь методы getResult/getNextResult/hasMoreResults принадлежат SqlStatement. Константы также берём у SqlStatement; наличие таких же чисел у Statement не превращает его в команду приложения. | объединяет флаги, ASYNC отделяет отправку от получения, BUFFERED выбирает буферизацию. true от execute означает отправку, а не готовый успешный результат.

Полная процедура и все проверки находятся в примере счёта: две лампы и кабель, всего 3200 копеек. Этот путь прочитал три ответа: позиции, сумму и пустое служебное завершение CALL. getResult может ждать сервер: ASYNC не обещает полностью неблокирующий PHP и не разрешает произвольно отправлять следующую команду на занятое соединение. Буферизация не заменяет WHERE/LIMIT для большого отчёта.

Когда возникает ошибка

Callback-путь имеет отдельный контракт: успешная запись и реальная квитанция и отказ повторного заказа показывают фактические события и сохранённые данные. Во втором случае ошибка 1062 прочитана из ответа, исходный ORDER-A остаётся с суммой 12.34, а следующий контрольный запрос работает. Не переносите эти callback-аргументы на Statement только по сходству названий. Полный читатель в тех программах относится именно к публичному SqlStatement.

Выбирайте один способ чтения конкретной последовательности. Цикл nextResult у результата и цикл getNextResult у команды — две разные организации чтения. Смешивание их на одном ответе лишает программу понятного владельца текущего состояния. Пустой набор строк, завершение набора и завершение всей команды — три разных события.

Класс и методы в справочнике

ИнструментЗадача
StatementРазличить зарегистрированный внутренний класс, публичную SQL-команду и полученный ответ, прежде чем переносить обработчик.
Statement::__constructПонять, почему закрытый конструктор является границей API и где получить нужную приложению команду.
Statement::getResultРазделить описание внутреннего читателя результата и доступное получение ответа публичной SQL-команды.
Statement::getNextResultНе перепутать переход к следующему ответу команды с чтением очередной строки текущего ответа.
Statement::hasMoreResultsПонять, какой вопрос задаёт проверка продолжения ответа, и не заменить её проверкой количества строк.

Почему возникают ошибки выбора объекта и чтения

Вопрос приводит к попыткам обхода конструктора через Reflection. Для нативного Statement это неверный путь к рабочей SQL-команде: объекту нужно внутреннее состояние драйвера. Мы исследуем только метаданные класса, а операции получаем через существующий публичный API. Чужой код обхода видимости не используется. Как работать с классом, у которого закрытый конструктор.

Проблема сформулирована для PDO: пустой массив приняли за отсутствие дальнейшего результата. Здесь раскрыта та же ошибка модели, но применяются методы X DevAPI и его собственные фактические результаты; PDO nextRowset не переносится в этот API. После пустого первого набора потерян полезный ответ процедуры.

Обсуждение MySQLi показывает нарушение порядка чтения. Наличие одного массива строк не означает, что весь ответ завершён. В X DevAPI выбираем один потребитель последовательности и дочитываем её перед следующим SQL. Рецепты free/close из другого драйвера не подменяют этот контракт. Следующий запрос отправлен до завершения ответа CALL.

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

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

Документированные узлы Statement сохранены в дереве и объяснены полностью в пределах доступного baseline. Это не заявление о проверенных прямых вызовах всех внутренних методов или полноте всего PHP Manual. Состояние поддержки относится к указанной версии расширения; перенос на другую версию начинается с проверки её фактического контракта.

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

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

mysql_xdevapi\StatementРазличить зарегистрированный внутренний класс, публичную SQL-команду и полученный ответ, прежде чем переносить обработчик.

Класс: PECL mysql-xdevapi >= 8.0.11. На страницах отдельных методов начальная версия не указана; исследуемая реализация — 8.0.30. · mysql_xdevapi

class mysql_xdevapi\Statement {
    const int EXECUTE_ASYNC = 1;
    const int BUFFERED = 2;
    public function getNextResult(): mysql_xdevapi\Result;
    public function getResult(): mysql_xdevapi\Result;
    public function hasMoreResults(): bool;
}
// Отдельная страница: private function __construct();

Различить зарегистрированный внутренний класс, публичную SQL-команду и полученный ответ, прежде чем переносить обработчик.

Официальная запись и её границы

class mysql_xdevapi\Statement {
    const int EXECUTE_ASYNC = 1;
    const int BUFFERED = 2;
    public function getNextResult(): mysql_xdevapi\Result;
    public function getResult(): mysql_xdevapi\Result;
    public function hasMoreResults(): bool;
}
// Отдельная страница: private function __construct();

Это обзор класса из PHP Manual, а не файл для объявления пользовательской копии. EXECUTE_ASYNC и BUFFERED — целые константы 1 и 2. В synopsis показаны три публичных метода; закрытый конструктор находится в оглавлении и на собственной странице. У класса нет публичного execute.

У класса нет единственного «возвращаемого значения»: результат относится к конкретному методу. В synopsis getResult/getNextResult записаны как Result, hasMoreResults — bool; отдельные страницы не объясняют окончания последовательности и отказов. Эти пропуски нельзя дополнять догадкой о фактическом объекте.

Страница класса отмечена PECL mysql-xdevapi >= 8.0.11. Введение и отдельные пояснения констант пусты. Matching 8.0.30 регистрирует Statement и SqlStatement раздельно, обеим регистрациям задаёт флаги 1/2. Число 1 выбирает разделение отправки/чтения в поддерживаемом пути, 2 — буферизацию; это не параметры конструктора. Не выдаём отсутствие описаний за официальное deprecated или дату удаления.

Применения без подмены объекта

Проверить совместимость обработчика перед переносом

Две проверки показывают, почему схема new Statement → execute не соответствует этому классу. Сначала class_exists(..., false), как в полном отчёте, затем чтение метаданных без конструктора.

$class = new ReflectionClass('mysql_xdevapi\\Statement');
$canCreate = $class->isInstantiable();
$hasExecute = $class->hasMethod('execute');
// Для 8.0.30: false и false.

Самостоятельная безопасная проверка метаданных

Получить сводку через публичную команду

В готовом отчёте отправлений первая часть пуста, а следующая содержит 2 отправления на 2700 копеек. Публичная фабрика команды — Session::sql, не конструктор Statement. Полный пример также показывает чтение до конца.

$command = $session->sql('CALL ' . $qualifiedProcedure . '()');
$result = $command->execute();
// Это SqlStatement и SqlStatementResult. Далее дочитайте все наборы.

Самостоятельная программа с фактическим результатом

Ошибки и связанные инструменты

Statement не надо имитировать собственной PHP-моделью, создавать сериализацией или через обход конструктора. Нативному объекту требуется корректный указатель и состояние команды. Reflection показывает форму API, но не доказывает выполнение запроса, состояние сети или полноту документации. Константы класса не означают, что у него есть метод execute.

Весь контракт Statement · Закрытый конструктор · Получение ответа · Следующий ответ · Продолжение последовательности.

mysql_xdevapi\Statement::__constructПонять, почему закрытый конструктор является границей API и где получить нужную приложению команду.

Класс: PECL mysql-xdevapi >= 8.0.11. На страницах отдельных методов начальная версия не указана; исследуемая реализация — 8.0.30. · mysql_xdevapi

private function mysql_xdevapi\Statement::__construct()

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

Официальная запись и её границы

private function mysql_xdevapi\Statement::__construct()

Параметров нет. private запрещает обычный внешний вызов конструктора. Отсутствие аргументов не означает, что нативный объект не нуждается во внутренней инициализации.

Конструктор не является фабрикой с отдельным результатом SQL. Его официальная страница не описывает поведение, кроме списка аргументов; приведён только пустой placeholder-пример.

Начальная версия отдельного метода не указана. Не переносим автоматически отметку класса >= 8.0.11 на утверждение о моменте появления каждой реализации. В matching исходнике пользовательский конструктор пуст, а create_stmt — внутренняя C++-функция: она связывает объект с нативной командой и инициализирует флаги. Это не функция PHP, которую приложение может вызвать по имени.

Применения без подмены объекта

Не запускать несовместимую ветку миграции

Диагностика даёт конкретное основание исправить код миграции. Объект ReflectionClass создан для чтения описания; Statement не создаётся.

$name = 'mysql_xdevapi\\Statement';
if (class_exists($name, false)) {
    $info = new ReflectionClass($name);
    $constructor = $info->getConstructor();
    $closed = $constructor !== null && $constructor->isPrivate();
}
// closed=true; обычное создание такого объекта не подходит.

Самостоятельная безопасная проверка метаданных

Подготовить нужный запрос без обхода конструктора

Фабрика Session::sql возвращает пригодный SqlStatement с состоянием команды. В полном отчёте счёта этот путь возвращает позиции и итог 3200 копеек; никакой объект Statement вручную не создаётся.

$command = $session->sql('CALL ' . $qualifiedProcedure . '()');
$sent = $command->execute(mysql_xdevapi\SqlStatement::EXECUTE_ASYNC | mysql_xdevapi\SqlStatement::BUFFERED);
// Затем getResult и полный цикл чтения у $command.

Самостоятельная программа с фактическим результатом

Ошибки и связанные инструменты

Обход видимости не заменяет внутреннее состояние библиотеки. Не вызывайте newInstanceWithoutConstructor, invoke конструктора или сериализацию ради получения «пустого» нативного Statement. Даже если инструмент Reflection технически поддерживает какие-то операции над другим классом, это не является разрешённым способом подготовить команду X DevAPI.

Весь контракт Statement · Закрытый конструктор · Получение ответа · Следующий ответ · Продолжение последовательности.

mysql_xdevapi\Statement::getResultРазделить описание внутреннего читателя результата и доступное получение ответа публичной SQL-команды.

Класс: PECL mysql-xdevapi >= 8.0.11. На страницах отдельных методов начальная версия не указана; исследуемая реализация — 8.0.30. · mysql_xdevapi

public function mysql_xdevapi\Statement::getResult(): mysql_xdevapi\Result

Разделить описание внутреннего читателя результата и доступное получение ответа публичной SQL-команды.

Официальная запись и её границы

public function mysql_xdevapi\Statement::getResult(): mysql_xdevapi\Result

Официальный список параметров пуст. Метод экземплярный, public, не static. Для вызова нужен корректно созданный нативный Statement; публичная документированная фабрика такого экземпляра для приложения в matching 8.0.30 не найдена.

Synopsis указывает mysql_xdevapi\Result, но раздел Return Values пуст, есть предупреждение о незадокументированности. Не описаны конец последовательности, отказ и callback-режим. Matching код передаёт вызов общему reader: без callback он создаёт SqlStatementResult при успешном чтении; другие ветви используют false, bool или исключение. Это вывод из исходника, а не объявленный здесь прямой runtime-тест Statement.

Версия отдельного метода не указана, пример на странице пустой. Reflection-метаданные нативной регистрации не задают тип возвращаемого значения, хотя Manual показывает Result. Отсутствие Reflection-типа не означает void или null: тип реального значения определяется выполнением корректного публичного сценария. Ноль объявленных параметров также не доказывает, что нативная реализация отвергает любые аргументы: общий reader содержит отдельный разбор callback-аргументов. Такой контракт устанавливают по исходнику и реальному публичному вызову, а не только по Reflection. Для практического чтения используем SqlStatement::getResult, а его экземпляр берём у Session::sql.

Применения без подмены объекта

Проверить контракт перед генерацией обёртки

Генератор обёртки не должен превращать отсутствие объявленного типа в утверждение «метод возвращает null» или обещать Result только по строке synopsis. Полный отчёт сохраняет именно наличие/отсутствие метаданных.

$info = new ReflectionClass('mysql_xdevapi\\Statement');
$reader = $info->getMethod('getResult');
$public = $reader->isPublic();
$declared = $reader->hasReturnType() ? (string)$reader->getReturnType() : null;
// public=true; declared=null в matching регистрации.

Самостоятельная безопасная проверка метаданных

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

В существующем полном примере первый ответ содержит две позиции: лампы и кабель. Это вызов SqlStatement::getResult, а не проверка экземпляра Statement. Остальные наборы и следующий контрольный запрос входят в тот же полный файл.

// $command — SqlStatement из уже отправленного ASYNC CALL.
$current = $command->getResult();
$rows = $current->getColumnsCount() > 0 ? $current->fetchAll() : [];
// Затем дочитайте остальные ответы по hasMoreResults/getNextResult.

Самостоятельная программа с фактическим результатом

Ошибки и связанные инструменты

Не вызывайте метод статически по имени класса и не подставляйте объект, созданный обходом конструктора. getResult не является fetchOne и не возвращает автоматически одну строку массива. У callback-потребителя другой результат чтения: его true/false нельзя обрабатывать как объект с fetchAll. Не смешивайте callback и обычное чтение одной последовательности.

Весь контракт Statement · Закрытый конструктор · Получение ответа · Следующий ответ · Продолжение последовательности.

mysql_xdevapi\Statement::getNextResultНе перепутать переход к следующему ответу команды с чтением очередной строки текущего ответа.

Класс: PECL mysql-xdevapi >= 8.0.11. На страницах отдельных методов начальная версия не указана; исследуемая реализация — 8.0.30. · mysql_xdevapi

public function mysql_xdevapi\Statement::getNextResult(): mysql_xdevapi\Result

Не перепутать переход к следующему ответу команды с чтением очередной строки текущего ответа.

Официальная запись и её границы

public function mysql_xdevapi\Statement::getNextResult(): mysql_xdevapi\Result

Официально метод не принимает аргументов. public означает видимость, а не наличие подходящего экземпляра у приложения. Метод экземплярный; рабочее внутреннее состояние обязательно.

В synopsis стоит Result, но текст Return Values пуст. Matching Statement::getNextResult вызывает тот же общий reader, что getResult. Поэтому страница не даёт достаточного контракта для угадывания конца, типа callback-ответа или поведения при ошибке. Новая программа не вызывает этот метод на искусственном Statement.

На отдельной странице нет версии, полного описания и рабочего примера. Внутренний reader различает буферизацию и callback-путь, может создать SqlStatementResult или завершиться отказом. Практически проверенный маршрут здесь — одноимённый метод SqlStatement после отправленного CALL и чтения текущего ответа. Тип объекта команды явно указан в каждом фрагменте.

Применения без подмены объекта

Не потерять итог после позиций счёта

В счёте после позиций идёт сумма 3200 копеек, а затем служебное завершение. Переход выполняется по состоянию команды, не по числу строк. Этот фрагмент — одна итерация полного проверенного потребителя SqlStatement.

// У $command (SqlStatement) уже прочитан текущий набор.
if ($command->hasMoreResults()) {
    $current = $command->getNextResult();
    $rows = $current->getColumnsCount() > 0 ? $current->fetchAll() : [];
}
// Продолжайте тот же цикл до завершения всей команды.

Самостоятельная программа с фактическим результатом

Обработать пустую первую часть другим поддерживаемым способом

Синхронный отчёт отправлений прочитал пустой список отмен и затем 2 готовых отправления на 2700 копеек. Здесь метод nextResult вызывается на результате и возвращает bool; это другой API, не Statement::getNextResult.

// $result — SqlStatementResult после обычного execute CALL.
do {
    $rows = $result->getColumnsCount() > 0 ? $result->fetchAll() : [];
    // Пустой список отмен не отменяет следующую сводку.
} while ($result->nextResult() === true);

Самостоятельная программа с фактическим результатом

Ошибки и связанные инструменты

Имя getNextResult не означает «следующая строка»: строки принадлежат текущему набору и читаются fetchOne/fetchAll. Не запускайте процедуру повторно ради получения следующей части. Не выбирайте одновременно двух потребителей — nextResult результата и getNextResult команды. Пустая часть может быть содержательным ответом либо служебным завершением; положение в протоколе определяется полной последовательностью, а не только [].

Весь контракт Statement · Закрытый конструктор · Получение ответа · Следующий ответ · Продолжение последовательности.

mysql_xdevapi\Statement::hasMoreResultsПонять, какой вопрос задаёт проверка продолжения ответа, и не заменить её проверкой количества строк.

Класс: PECL mysql-xdevapi >= 8.0.11. На страницах отдельных методов начальная версия не указана; исследуемая реализация — 8.0.30. · mysql_xdevapi

public function mysql_xdevapi\Statement::hasMoreResults(): bool

Понять, какой вопрос задаёт проверка продолжения ответа, и не заменить её проверкой количества строк.

Официальная запись и её границы

public function mysql_xdevapi\Statement::hasMoreResults(): bool

Параметров нет. Это public-метод экземпляра, который читает состояние инициализированной нативной команды. Наличие записи метода в Reflection не разрешает вызывать его на объекте без команды.

Synopsis обещает bool; отдельного текстового пояснения Return Values нет. Matching реализация обращается к has_more_results нативного stmt. Она не выполняет SELECT COUNT(*), не возвращает число строк и не проверяет доступность нового подключения. Прямой пользовательский Statement в этой главе не создаётся.

Версия метода не указана; документация ограничена аргументами и placeholder-примером. Значение относится к последовательности ответов уже выполняющейся команды. Фактическую логику публичного SqlStatement проверяли в отдельном примере: после полного чтения его последней части получено false и затем успешно выполнен новый SELECT.

Применения без подмены объекта

Определить переход после чтения части отчёта

В отчёте счёта проверка после последних данных позволила прочитать ещё и пустое служебное завершение. После него false, а следующий SQL снова доступен. Ни count($rows), ни пустой массив не служат заменой этой проверке.

// $command — отправленный SqlStatement, $current уже прочитан.
$more = $command->hasMoreResults();
if ($more) {
    $current = $command->getNextResult();
}
// false завершает цикл этой последовательности.

Самостоятельная программа с фактическим результатом

Не признать отказ успешно сохранённым заказом

В проверенном consumer повторный ORDER-A дал ошибку 1062; исходная сумма 12.34 сохранилась, а следующий SELECT прошёл. Конец чтения означает завершение обработки ответа, но не отсутствие серверной ошибки. Полный файл сохраняет обе части этого вывода.

// После полного callback-чтения публичного SqlStatement:
$finished = !$command->hasMoreResults();
// finished само по себе не означает успешную запись.
// Отдельно проверьте сохранённые ошибки и реальную строку заказа.

Самостоятельная программа с фактическим результатом

Ошибки и связанные инструменты

Не опрашивайте метод до отправки команды в надежде проверить «живость» соединения. Не путайте hasMoreResults с hasData у результата: один вопрос о продолжении последовательности, другой о данных текущей части. ASYNC не снимает необходимость дочитать ответ. Возможность следующего запроса проверяется после завершения корректного чтения, а не созданием другого неинициализированного объекта.

Весь контракт Statement · Закрытый конструктор · Получение ответа · Следующий ответ · Продолжение последовательности.

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

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

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

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

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