Почему кэш в Bitrix «сходит с ума» в рабочей области (WORKAREA)

Share

Если ты когда-нибудь замечал, что один и тот же компонент на разных страницах создает разные файлы кэша, хотя параметры (arParams) идентичны — поздравляю, ты столкнулся с особенностью обработки WORKAREA.

1. Роль глобальной переменной BX_STATE

В ядре Bitrix существует переменная (или состояние), которая определяет, где именно исполняется код компонента.

  1. Вне WORKAREA (шапка, подвал, сайдбары): Компонент считается «сквозным». Его кэш привязан только к входным параметрам.
  2. Внутри WORKAREA: Bitrix предполагает, что контент в центральной части сайта уникален для каждого URL. Поэтому система автоматически подмешивает текущий путь к странице в идентификатор кэша (cache_id).

2. Проблема фильтрации и ЧПУ

Когда ты используешь фильтр, URL страницы меняется (например, добавляются параметры или меняется путь в ЧПУ). Для Bitrix внутри WORKAREA это сигнал: «Это новая страница, старый кэш не подходит, генерируй новый». В итоге папка /bitrix/cache/ раздувается, а сервер тратит ресурсы на создание дублей для каждой комбинации фильтра.

Как приручить кэш: Практические советы

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

Способ 1: Явное управление путем кэша

При вызове метода StartResultCache (или его аналогов в D7) можно передать путь к папке кэша. Если ты укажешь его явно, Bitrix перестанет автоматически привязывать компонент к URL текущей страницы.

// Внутри component.php
if ($this->StartResultCache(false, $additionalCacheID, "/my_custom_cache_path")) {
// ... логика ...
$this->IncludeComponentTemplate();
}

Способ 2: Формирование уникального additionalCacheID

Если тебе нужно, чтобы кэш зависел только от выбранных фильтров, но игнорировал URL, сформируй свой ID на основе массива фильтрации.

  1. Возьми только нужные ключи из $_GET или $arParams.
  2. Сериализуй их и передай как второй параметр в StartResultCache.

Способ 3: Ручное кэширование тяжелых данных (CPHPCache)

Для фильтров лучше всего кэшировать не весь компонент с его HTML-шаблоном, а только «тяжелые» данные (например, результат запроса к БД) с помощью класса CPHPCache или Bitrix\Main\Data\Cache. Это позволит:

  1. Использовать один и тот же результат на разных страницах.
  2. Точно контролировать, от каких параметров зависит кэш.


Способ 4: Временная смена «статуса» (Тот самый костыль)

Битрикс определяет, находится ли он в рабочей области, по значению переменной $GLOBALS["BX_STATE"]. Обычно она принимает значение 'wa' (Work Area) во время вывода основного контента.

Если ты хочешь обмануть систему и сделать вид, что компонент вызывается где-то в «сайдбаре» (чтобы кэш не привязывался к URL), можно сделать так:

// Сохраняем текущее состояние
$oldState = $GLOBALS["BX_STATE"];

// Выключаем режим "Work Area"
$GLOBALS["BX_STATE"] = "custom";

$APPLICATION->IncludeComponent(
"bitrix:catalog.section",
"",
Array(
// твои параметры
)
);

// Возвращаем всё как было, чтобы не сломать кэш последующих компонентов
$GLOBALS["BX_STATE"] = $oldState;

Почему это работает:

Внутри метода StartResultCache Битрикс проверяет: если BX_STATE === 'wa', то в cache_id автоматически дописывается текущий SITE_DIR и путь к странице. Меняя значение на любое другое (или зануляя его), ты отключаешь эту автоматику.

Плюсы:

  1. Скорость: Не нужно переписывать логику кэширования внутри компонента.
  2. Универсальность: Работает со всеми стандартными компонентами «из коробки».

Минусы (предупреждение):

  1. Опасность: Если забудешь вернуть старое значение, все последующие компоненты на странице тоже могут «потерять» привязку к URL, что вызовет кашу в контенте.
  2. Чистота кода: Это прямое вмешательство в глобальные переменные ядра, что считается «плохим тоном» в современной разработке (D7), но в пылу борьбы с фильтрами — вполне себе спасение.


Итоговый совет: Если ты пишешь свой компонент — лучше используй явный путь к кэшу (Способ 1). Если мучаешься с чужим/стандартным — твой способ с переопределением BX_STATE идеален.