УрокСистема кэширования Drupal 7. Часть вторая: программное управление кэшем.

Сегодня наконец дошли руки написать продолжение серии статей о кэшировании. В первой части были рассмотрены сегменты кэша, которые находятся в ядре седьмого Друпала. Сегодня же мы поговорим о том, как работать с кэшем программно. Для примера создадим модуль, который предоставляет свой сегмент кэша и управление им.

Шаг первый. Создание нового сегмента кэша.

Назовём наш модуль, например, Example cache. Для создания своего сегмента кэша практически всегда используется клон стандартной таблицы {cache}, поэтому и мы не будем исключением. В example_cache.install имплементируем hook_schema(), чтобы добавить свою таблицу:

/**
 * Implements hook_schema().
 */
function example_cache_schema() {
 
  $schema['cache_example'] = drupal_get_schema_unprocessed('system', 'cache');
  $schema['cache_example']['description'] = 'Cache table stores some example data.';
 
  return $schema;
}

В принципе всё. Теперь при инсталяции модуля в базе данных будет создана новая таблица с необходимыми полями.

Шаг второй. Заботимся о сбросе кэша.

Вторым шагом я обычно сразу делаю то, о чём в самом конце можно забыть - предусмотреть автоматический сброс кэша. При нажатии на кнопку "Очистка кэша" в разделе "Производительность" (/admin/config/development/performance) должны очиститься все таблицы (сегменты) с кэшем. И наш только что добавленный сегмент не должен быть исключением. Для этого в example_cache.module имплементируем hook_flush_caches(). Он возвращает названия сегментов (таблиц), которые будут очищены при общем сбросе кэша:

/**
 * Implements hook_flush_caches().
 */
function example_cache_flush_caches() {
  return array('cache_example');
}

Шаг третий. Кэшируем данные.

Давайте теперь для разнообразия закэшируем какие-нибудь данные. Для наглядности я решил закэшировать бесполезную, но достаточно длительную операцию по заполнению массива миллионом элементов. Повесим эту операцию, например, на hook_init():

/**
 * Implements hook_init().
 */
function example_cache_init() {
 
  timer_start('example_cache');
 
  $array = array();
  for ($i = 0; $i < 1000000; $i++) {
    $array[] = $i;
  }
 
  $timer = timer_read('example_cache') / 1000;
  drupal_set_message('Мы получили результат за ' . $timer . ' секунд');
 
}

Как видите, пока никакого кэша нет. У меня эта операция выполняется примерно две секунды. А теперь давайте добавим сюда кэширование:

/**
 * Implements hook_init().
 */
function example_cache_init() {
 
  timer_start('example_cache');
 
  // Указываем любое уникальное имя.
  $cache_id = 'some_unique_name';
 
  // Пытаемся получить результат из нашего сегмента кэша.
  $cache = cache_get($cache_id, 'cache_example');
 
  // Если результат был найден в кэше - то просто забираем его.
  if (!empty($cache->data)) {
    $array = $cache->data;
  }
  else {
    // Если же результат не был найден, то вычисляем его и сохраняем в кэше.
    $array = array();
    for ($i = 0; $i < 1000000; $i++) {
      $array[] = $i;
    }
 
    // Сохраняем результат в кэше на 15 минут.
    cache_set($cache_id, $array, 'cache_example', REQUEST_TIME + 15 * 60);
  }
 
  $timer = timer_read('example_cache') / 1000;
  drupal_set_message('Мы получили результат за ' . $timer . ' секунд');
}

После добавления кэша время выполнения этой функции существенно уменьшилось.

В принципе, это единственный верный способ работы с кэшем и другого пока не придумано. Однако на практике могут применяться ещё несколько функций. Давайте рассмотрим их все.

Сохранение данных в кэше

Для добавления данных в хранилище кэша используется функция cache_set. Она имеет следующие параметры:

  • $cid - уникальный Cache ID (primary key) хранимых данных.
  • $data - данные в любом формате, которые надо закэшировать. Данные автоматически сериализуются.
  • $bin - сегмент кэша (в нашем случае - таблица в бд), куда надо сохранить данные. Если не указать этот параметр, то данные будут храниться в {cache}.
  • $expire - задаёт срок годности кэша в милисекундах (Unix timestamp). Он задаётся прибавлением необходимого времени жизни кэша к текущему времени. Кроме числового значения этот параметр может принимать значения CACHE_PERMANENT или CACHE_TEMPORARY. В первом случае данные не будут удалены из кэша, пока вы их не удалите принудительно (очисткой сегмента либо же удалением данных с указанным $cid). Во втором случае данные будут очищены при первой же общей очистке кэша с истёкшим сроком годности.

Получение кэшированных данных

Для получения данных из кэша используется функция cache_get. Её параметры:

  • $cid - Cache ID - уникальный идентификатор кэша, который надо получить.
  • $bin - сегмент кэша (в нашем случае - таблица в бд), откуда надо забрать результат. Если не передать этот параметр, то данные будут браться из сегмента {cache}.

Если данных в кэше нет, либо же у него истёк срок годности (когда текущее время больше времени срока годности кэша), то возвращается пустой результат.

Для получения результата так же может использоваться функция cache_get_multiple. Первый её параметр отличается от cache_get лишь тем, что она принимает набор (массив) cid'ов, данные для которых надо получить. После вызова cache_get_multiple из этого массива удаляются все cid'ы, для которых был найден результат.

Очистка (сброс) кэша

Для удаления кэшированных данных используется функция cache_clear_all. Её параметры:

  • $cid - Cache ID, который надо удалить из хранилища данных. Если не указан, то будут удалены все данные с истёкшим сроком годности и c CACHE_TEMPORARY.
  • $bin - название сегмента кэша, из которого надо удалить данные. Если указан указан $cid, то этот аргумент обязателен.
  • $wildcard - если указан как TRUE, то все записи, у которых Cache ID начинается с $cid будут удалены. Если $cid имеет значение *, то будет очищен весь сегмент.

Несколько примеров использования:

// Очищает кэш с истёкшим сроком годности и CACHE_TEMPORARY
// из {cache_block} и {cache_page}.
cache_clear_all();
 
// Полностью очищает сегмент {cache_example}.
cache_clear_all('*', 'cache_example', TRUE);
 
// Удаляет из сегмента {cache} запись с Cache ID равным 'my_module'.
cache_clear_all('my_module');
 
// Удаляет из сегмента {cache_example} записи, у которых
// Cache ID начинается c 'my_module'.
cache_clear_all('my_module', 'cache_example', TRUE);

Проверка на наличие данных в кэше

С помощью функции cache_is_empty можно узнать, хранятся ли в сегменте кэша какие-либо данные. Достаточно малоиспользуемая функция, но тем не менее помнить про неё надо.

Примеры использования

В качестве примера работы с кэшем вы можете установить модуль Cache Example, находящийся в составе модуля Examples.