Например, список новостей сайта идентичен для всех посетителей. Поэтому нет смысла выбирать данные каждый раз из базы. Время кеширования зависит в основном от частоты ввода новых новостей.
Иногда может иметь смысл и кеширование зависящей от конкретного посетителя информации.
[spoiler]
Встроенная поддержка кеширования
В компонентах 2.0 есть встроенная поддержка типичного алгоритма кеширования. Структура компонента с использованием встроенной поддержки кеширования будет примерно такова
// Проверка и инициализация входных параметров if ($arParams["ID"] <= 0) $arParams["ID"] = 10; // Если нет валидного кеша (то есть нужно запросить // данные и сделать валидный кеш) if ($this->StartResultCache()) { // Запрос данных и заполнение $arResult $arResult = array( "ID" => rand(1, 100) ); for ($i = 0; $i < 5; $i++) $arResult["FIELDS"][] = rand(1, 100); // Если выполнилось какое-то условие, то кешировать // данные не надо if ($arParams["ID"] < 10) $this->AbortResultCache(); // Подключить шаблон вывода $this->IncludeComponentTemplate(); } // Установить заголовок страницы с помощью отложенной // функции $APPLICATION->SetTitle($arResult["ID"]); |
Пояснения по коду:
Метод StartResultCache имеет следующее описание
bool $this->StartResultCache($cacheTime = False, $additionalCacheID = False, $cachePath = False)
где
$cacheTime - время кеширования (если False - подставляется IntVal($arParams["CACHE_TIME"])),
$additionalCacheID - от чего дополнительно зависит кеш кроме текущего сайта SITE_ID, имени компонента, путя в файлу и входных параметров $arParams (если False - кеш зависит только от указанных параметров),
$cachePath - путь к файлу кеша (если False - подставляется "/".SITE_ID.<путь к компоненту относительно bitrix/components>).
Если есть валидный кеш, то метод отправляет на экран его содержимое, заполняет $arResult и возвращает False; если нет валидного кеша, то он возвращает True.
Если кеш зависит не только от сайта, входных параметров, имени компонента и пути к текущему сайту, но и от других параметров, то эти параметры в виде строки нужно передать в метод вторым параметром. Например, если кеш зависит еще от групп пользователей, в которые входит текущий посетитель, то условие нужно написать следующим образом
if ($this->StartResultCache(false, $USER->GetGroups())) { // Валидного кеша нет. Выбираем данные из // базы в $arResult } |
Если в результате выборки данных (в случае отсутствия валидного кеша) выяснилось, что кешировать данные не надо, то нужно вызвать метод
$this->AbortResultCache();
Например, если выяснолось, что новости с таким ID нет, то нужно прервать кеширование и выдать сообщение, что такой новости нет. Если кеширование не прерывать, то злоумышленники смогут забить кешем все отведенное сайту дисковое пространство вызывая страницу с произвольными (в том числе и не существующими) ID.
Метод
$this->IncludeComponentTemplate();
подключает шаблон компонента и сохраняет в кеш-файл вывод и массив результатов $arResult. Все изменения $arResult и вывод после вызова метода подключения шаблона не будут сохранены в кеш.
Если при исполнении кода компонента мы не вошли в тело условия
if ($this->StartResultCache())
значит для данного компонента, страницы и входных параметров есть валидный кеш. После вызова этого метода HTML из кеша отправлен на вывод и мы имеем заполненный массив $arResult. Здесь можно выполнить некоторые действия. Например, установить заголовок страницы с помощью отложенных функций.
Если при выполнении некоторых условий нужно очистить кеш компонента (например, компонент знает, что данные изменились), то можно воспользоваться методом
$this->ClearResultCache($additionalCacheID = False, $cachePath = False)
Параметры этого метода соответствуют одноименным параметрам метода StartResultCache.
Сложное кеширование
Если компоненту требуется какое-либо особое кеширование, которое не может быть выполнено с помощью встроенной поддержки кеширования, то можно использовать стандартный класс CPHPCache.
Структура компонента с использованием класса CPHPCache будет примерно такова
// Проверка и инициализация входных параметров if ($arParams["ID"] <= 0) $arParams["ID"] = 10; $arParams["CACHE_TIME"] = IntVal($arParams["CACHE_TIME"]); $CACHE_ID = SITE_ID."|".$APPLICATION->GetCurPage()."|"; // Кеш зависит только от подготовленных параметров без "~" foreach ($this->arParams as $k => $v) if (strncmp("~", $k, 1)) $CACHE_ID .= ",".$k."=".$v; $CACHE_ID .= "|".$USER->GetGroups(); $cache = new CPageCache; if ($cache->StartDataCache($arParams["CACHE_TIME"], $CACHE_ID, "/".SITE_ID.$this->GetRelativePath())) { // Запрос данных и формирование массива $arResult $arResult = array("a" => 1, "b" => 2); // Подключение шаблона компонента $this->IncludeComponentTemplate(); $templateCachedData = $this->GetTemplateCachedData(); $cache->EndDataCache( array( "arResult" => $arResult, "templateCachedData" => $templateCachedData ) ); } else { extract($cache->GetVars()); $this->SetTemplateCachedData($templateCachedData); } |
Пояснения по коду:
Кеш должен зависеть только от подготовленных параметров. То есть от параметров, которые инициализированы нужным образом, приведены к нужному типу (например, с помощью IntVal()) и т.д. В массиве $arParams содержатся как подготовленные параметры, так и исходные параметры (с тем же ключем, но с префиксом "~"). Если кеш будет зависеть от неподготовленных параметров, то злоумышленники смогут забить кешем все отведенное сайту дисковое пространство вызывая страницу с ID равными "8a", "8b", ... (которые после IntVal() дадут 8).
Метод
$this->IncludeComponentTemplate()
не запрашивает данные из базы. Но его тоже лучше включить в кешируемую область, так как этот метод производит определенные дисковые операции.
Перед вызовом метода завершения кеширования и сохранения кеша (метод EndDataCache) необходимо запросить у шаблона параметры, которые должны быть использованы даже в том случае, если сам шаблон не подключается и данные берутся из кеша. В текущей реализации такими параметрами являются стили css шаблона, которые подключаются отложенными функциями, а значит не попадают в кеш. Структура возвращаемых шаблоном данных не документирована и не имеет значения для компонента. Это просто какие-то данные, которые нужно положить в кеш, а затем взять из кеша и вернуть в шаблону.
Для того, чтобы вернуть шаблону те данные, которые он просил сохранить в кеше, можно пользоваться методами
$this->SetTemplateCachedData($templateCachedData);
или
CBitrixComponentTemplate::ApplyCachedData($templateCachedData);
Один из этих методов должен быть вызван в той области компонента, которая выполняется в случае наличия валидного кеша. В параметрах ему должны быть переданы те данные, которые шаблон просил сохранить.
А так все работает, большое спасибо за раздел "Сложное кеширование"
Поправка досадная - в случае отложенной отработки шаблонизатора кэш в стандартных компонентах просто не будет работать.