Collection::sortByColumn: сортировка массива строк по нескольким колонкам

21.09.2026

Проблема/контекст

Данные собраны из нескольких источников: остатки из внешнего API, цены из ORM, рейтинг из кеша. Отсортировать результат в SQL уже нельзя, и в коде появляется usort() с замыканием на десять строк и тремя <=>. В ядре для этого есть Bitrix\Main\Type\Collection. Класс старый, в новой документации его нет, и у sortByColumn() есть поведение, которое по сигнатуре не угадать.

Решение с кодом

        <?php
declare(strict_types=1);

use Bitrix\Main\Type\Collection;

$rows = [
    ['ID' => 7, 'STORE' => 'Склад Б', 'QUANTITY' => '15', 'PRICE' => 990.0],
    ['ID' => 3, 'STORE' => 'склад а', 'QUANTITY' => '9'],
    ['ID' => 5, 'STORE' => 'Склад А', 'QUANTITY' => '15', 'PRICE' => 1200.0],
];

Collection::sortByColumn(
    array: $rows,                               // массив $rows передаётся в метод по ссылке
    columns: [
        'QUANTITY' => [SORT_NUMERIC, SORT_DESC],
        'STORE' => SORT_ASC,
    ],
    callbacks: ['STORE' => 'mb_strtolower'],    // значение колонки проходит через callback перед сравнением
    defaultValueIfNotSetValue: 0,               // подставляется, если колонки в строке нет
    preserveKeys: true,                         // сохранить ключи массива
);

print_r($rows);

    

Короткая форма Collection::sortByColumn($rows, 'PRICE') равна ['PRICE' => SORT_ASC].

Внутри метод вынимает каждую колонку в отдельный массив и вызывает array_multisort(), передавая исходный массив последним аргументом. Отсюда четыре момента.

  1. Флаги сортировки те же, что у array_multisort(): SORT_NUMERIC, SORT_STRING, SORT_NATURAL, SORT_FLAG_CASE. Количество '15' и '9' без SORT_NUMERIC сравнится как строки.
  2. Массив сортируется по ссылке, метод ничего не возвращает. Без пятого аргумента числовые ключи перенумеровываются. Если ключами были ID элементов, они пропадут.
  3. При полном равенстве по всем колонкам array_multisort() переходит к следующему аргументу, то есть сравнивает строки целиком как массивы. Порядок получается детерминированным, но зависит от содержимого остальных полей. Если при равенстве важен исходный порядок, добавьте последней колонкой порядковый номер.
  4. Callback должен быть callable. Опечатка в имени функции даёт ArgumentOutOfRangeException('callbacks'). Один callback строкой применяется ко всем колонкам, массив вида колонка => callback действует выборочно.

В том же классе есть методы для вложенных массивов:

        $options = ['delivery' => ['pickup' => ['enabled' => true]]];

Collection::getByNestedKey($options, ['delivery', 'pickup', 'enabled']); // true
Collection::getByNestedKey($options, ['delivery', 'courier', 'enabled']); // null
Collection::setByNestedKey($options, ['delivery', 'courier', 'enabled'], false);

    

getByNestedKey() возвращает null для отсутствующего ключа, но на каждом шаге вызывает array_key_exists() для текущего значения. Если по пути встретился скаляр (['delivery' => 'off']), PHP 8 бросит TypeError. setByNestedKey() создаёт промежуточные массивы сам, а на пустом пути бросает ArgumentException.

Итог

sortByColumn() заменяет самописные компараторы для табличных данных. Указывайте SORT_NUMERIC для чисел в строках и пятый аргумент, когда ключи массива имеют значение.

Опубликовано 18 часов назад

Комментарии (0)

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

Оставить комментарий
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти