Почти каждый метод старого API Битрикса — CUser::GetList,
CIBlockElement::GetList, прямой запрос через
$DB->Query — возвращает не готовый массив данных,
а объект CDBResult. Разберём, как этот объект устроен
и какие его методы регулярно путают между собой.
Fetch vs GetNext
<?php
$result = CUser::GetList('ID', 'ASC', []);
// вариант 1
while ($row = $result->Fetch()) {
echo $row['LOGIN'];
}
// вариант 2 (для инфоблоков — с дополнительной логикой полей)
while ($row = $result->GetNext()) {
echo $row['LOGIN'];
}
Fetch() — базовый метод получения следующей строки
как ассоциативного массива, доступный у любого объекта
CDBResult. GetNext() — специфичный
для некоторых наследников (например, результата
CIBlockElement::GetList) метод, который дополнительно
выполняет форматирование значений полей — например, подстановку
полного пути к файлам вместо ID файла. Использование не того метода
не вызовет ошибки, но может дать данные в неожиданном формате
(сырой ID файла вместо готового пути).
Постраничная навигация: NavStart
<?php
$result = CUser::GetList(
'ID', 'ASC', [],
['NAV_PARAMS' => ['nPageSize' => 20]]
);
$result->NavStart();
while ($row = $result->NavNext()) {
echo $row['LOGIN'];
}
echo $result->NavPrintPagesBar(); // готовый HTML постраничной навигации
Постраничная навигация встроена прямо в объект результата —
NavStart инициализирует текущую страницу
(по умолчанию берётся из GET-параметра запроса), NavNext
проходит по строкам текущей страницы, а
NavPrintPagesBar генерирует готовый блок ссылок
постраничной навигации без ручной вёрстки этой логики с нуля.
Нужна помощь с Битрикс?
Получение общего количества записей
<?php
echo $result->NavRecordCount; // общее число записей во всей выборке
echo $result->SelectedRowsCount(); // число строк на текущей странице
Различие между этими значениями регулярно путают: одно — общее число записей, соответствующих фильтру, по всей выборке целиком, другое — сколько строк реально попало именно в текущую порцию (страницу) результата. Использование не того значения ломает логику вроде "показать общее количество найденных товаров" на странице каталога.
Прямое обращение к массиву вместо цикла Fetch
<?php
$items = [];
$result = CUser::GetList('ID', 'ASC', []);
while ($row = $result->Fetch()) {
$items[] = $row;
}
// $items теперь обычный массив, с которым удобнее работать дальше,
// например, через array_map или array_filter
Частый практический приём — сразу после получения результата
собрать его в обычный PHP-массив через цикл, а не носить объект
CDBResult дальше по коду, — обычный массив проще
передавать между функциями и обрабатывать стандартными функциями
массивов PHP, тогда как объект результата рассчитан именно
на последовательный проход, а не на произвольный доступ к элементам.
Однократность обхода
Объект CDBResult — это курсор, а не хранилище данных
целиком: пройти по нему циклом Fetch() можно только
один раз, повторный вызов цикла на том же объекте вернёт пустой
результат, поскольку внутренний указатель уже находится в конце.
Если данные нужны для повторного использования в нескольких местах
кода, их стоит собрать в обычный массив один раз, а не пытаться
обойти один и тот же объект результата дважды.
Частые ошибки
- Использован Fetch там, где нужен GetNext, или наоборот. Значения полей приходят в сыром виде вместо ожидаемого форматированного, или наоборот.
- Перепутаны NavRecordCount и SelectedRowsCount. Неверное отображение общего числа найденных записей на странице с пагинацией.
- Попытка повторно обойти уже пройденный объект результата. Второй проход возвращает пустой результат из-за исчерпанного внутреннего курсора.
Итог
CDBResult — курсор для однократного последовательного
прохода по результату выборки, а не готовый массив данных. Разница
между Fetch и GetNext, а также между
общим количеством записей и количеством строк на текущей странице —
источник регулярной путаницы, которую стоит держать в голове
при работе со старым API Битрикса.
