walk() для ORM-коллекций: практичные массовые операции с инфоблоками

25.02.2026

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

В D7 вы часто получаете из ORM не массив, а типизированную коллекцию объектов через fetchCollection(). Перебирать её через foreach нормально, но в реальном коде обычно хочется:

  • компактно “пройтись и изменить” объекты;
  • сохранить изменения одной цепочкой вызовов;
  • не плодить лишние временные переменные.

Начиная с main 26.0.0 у Bitrix\Main\ORM\Objectify\Collection появился метод walk(): это “аналог foreach, но как метод”, который удобно вставляется в цепочку.

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

walk() вызывает ваш callback для каждого объекта коллекции и возвращает эту же коллекцию (для чейнинга). В callback приходят:

  1. объект сущности,
  2. ключ итерации — это ключ внутреннего массива коллекции (обычно сериализованный первичный ключ; для составного — строка).

Пример 1. Массово деактивировать элементы инфоблока и сохранить одной цепочкой

Частый кейс: найти элементы по условию, поставить ACTIVE = 'N' и сохранить максимально “чисто”.

        <?php
declare(strict_types=1);

use Bitrix\Iblock\ElementTable;
use Bitrix\Main\Loader;

function deactivateSectionElements(int $iblockId, int $sectionId): void
{
	Loader::includeModule('iblock');

	$saveResult = ElementTable::query()
		->setSelect(['ID', 'ACTIVE', 'IBLOCK_ID', 'IBLOCK_SECTION_ID'])
		->where('IBLOCK_ID', $iblockId)
		->where('IBLOCK_SECTION_ID', $sectionId)
		->where('ACTIVE', 'Y')
		->fetchCollection()
		->walk(static function($element): void {
			$element->setActive('N');
		})
		->save()
	;

	if (!$saveResult->isSuccess())
	{
		throw new \RuntimeException(implode('; ', $saveResult->getErrorMessages()));
	}
}

    

Практические детали:

  • При одинаковом изменении для всех объектов save() умеет выполнять групповой UPDATE (однотипные правки). Это как раз тот случай, когда walk() хорошо “стыкуется” с коллекциями.
  • Если вы меняете разные значения для каждого объекта (например, SORT по формуле), ORM может уйти в серию UPDATE по одному объекту.

Пример 2. “Пройтись и собрать” данные без лишнего foreach

walk() удобен не только для мутаций, но и для побочных эффектов: собрать ID, составить карту, подсчитать суммы.

        <?php
declare(strict_types=1);

use Bitrix\Iblock\ElementTable;
use Bitrix\Main\Loader;

function collectElementIdsAndNames(int $iblockId, int $limit = 50): array
{
	Loader::includeModule('iblock');

	$ids = [];
	$namesById = [];

	ElementTable::query()
		->setSelect(['ID', 'NAME'])
		->where('IBLOCK_ID', $iblockId)
		->setLimit($limit)
		->fetchCollection()
		->walk(static function($element, $key) use (&$ids, &$namesById): void {
			$id = (int)$element->getId();
			$ids[] = $id;
			$namesById[$id] = (string)$element->getName();
		})
	;

	return [
		'ids' => $ids,
		'namesById' => $namesById,
	];
}

    

Пример 3. Когда walk() лучше, чем filter()

У коллекции есть “функциональный” filter(), но он не сработает, если в коллекции есть несохранённые изменения — тогда выбрасывается CollectionFilterException.

Поэтому практическое правило такое:

  • хотите “сначала отобрать, потом поменять” — делайте filter() первым шагом;
  • хотите просто “пройтись и поменять” — берите walk().
        <?php
declare(strict_types=1);

use Bitrix\Iblock\ElementTable;
use Bitrix\Main\Loader;

function deactivateActiveElementsInIblock(int $iblockId): void
{
	Loader::includeModule('iblock');

	$saveResult = ElementTable::query()
		->setSelect(['ID', 'ACTIVE'])
		->where('IBLOCK_ID', $iblockId)
		->fetchCollection()
		->filter(static fn($element) => $element->getActive() == 'Y')
		->walk(static function($element): void {
			$element->setActive('N');
		})
		->save();

	if (!$saveResult->isSuccess())
	{
		throw new \RuntimeException(implode('; ', $saveResult->getErrorMessages()));
	}
}

    

Ограничения, о которых полезно помнить

  • walk() не даёт “прервать” обход по условию. Если нужен ранний выход — используйте foreach или find() у коллекции.
  • В callback вторым аргументом приходит ключ итерации. Он удобен для отладки/логики по PK, но не стоит на него “завязывать” бизнес-логику (особенно при составных ключах).

Итог

walk() — маленький метод, но в D7 он хорошо раскрывается именно в связке fetchCollection() -> walk() -> save(): получается компактный, читабельный и часто более производительный массовый апдейт.

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

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

0 / 100

Привет! Я помогу с вопросами по 1С-Битрикс.

Спрашивай про D7, ORM, компоненты или события.

Требуется авторизация

Войдите или зарегистрируйтесь, чтобы задавать вопросы AI-ассистенту.

Войти