Сайт на Yii2 работает быстро, пока данных мало. Но стоит базе подрасти, и страницы начинают грузиться вечность. Знакомо? Кеширование решает эту проблему, но многие боятся его настраивать. На самом деле всё проще, чем кажется. В этой статье разберём, как построить систему кеширования в Yii2, чтобы сайт летал, а вы спали спокойно.
Зачем вообще нужно кеширование в Yii2
Представьте, что каждый раз, когда вы открываете страницу, сервер заново собирает все данные: лезет в базу, обрабатывает, формирует HTML. Это как каждый раз готовить борщ с нуля, даже если кастрюля уже стоит в холодильнике. Кеш — это та самая кастрюля: один раз приготовили, а потом только разогреваем. В Yii2 кеширование встроено на уровне фреймворка, и его можно использовать где угодно: для фрагментов страниц, данных, запросов к БД и даже для целых ответов.
Основные плюсы: снижение нагрузки на базу, ускорение отклика, экономия ресурсов сервера. Минусы: данные могут устаревать, нужна стратегия инвалидации. Но об этом позже.
Настраиваем компонент кеша
По умолчанию в Yii2 уже есть компонент cache, который использует файловый кеш. Для небольших проектов этого достаточно. Но если нагрузка растёт, лучше переключиться на Memcached или Redis. Настройка делается в конфиге приложения (обычно config/web.php или config/main.php).
Вот пример для файлового кеша (по умолчанию):
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
],
А так можно подключить Memcached:
'components' => [
'cache' => [
'class' => 'yii\caching\MemCache',
'servers' => [
[
'host' => 'localhost',
'port' => 11211,
'weight' => 100,
],
],
],
],
Для Redis:
'components' => [
'cache' => [
'class' => 'yii\redis\Cache',
'redis' => [
'hostname' => 'localhost',
'port' => 6379,
'database' => 0,
],
],
],
После настройки можно обращаться к кешу через Yii::$app->cache.
Простые операции с кешем: get и set
Самые базовые методы — get() и set(). Выглядит это так:
$key = 'my_data_key';
$data = Yii::$app->cache->get($key);
if ($data === false) {
// данных в кеше нет, вычисляем
$data = heavyFunction();
Yii::$app->cache->set($key, $data, 3600); // кешируем на час
}
return $data;
Здесь heavyFunction() — это какая-то тяжёлая операция (запрос к БД, вызов API). Если данных нет, выполняем и сохраняем. Время жизни указывается в секундах. Если не указать, кеш будет храниться вечно (пока не очистится вручную).
Также есть метод add() — он сохраняет значение, только если ключа ещё нет. Удобно для блокировок.
Кеширование фрагментов страницы
Часто нужно закешировать не данные, а готовый HTML-блок. Например, меню, список категорий или виджет. В Yii2 для этого есть виджет FragmentCache или обёртка $this->beginCache() / $this->endCache() в представлениях.
Пример:
<?php if ($this->beginCache('category_list', ['duration' => 3600])): ?>
<ul>
<?php foreach ($categories as $category): ?>
<li><?= Html::encode($category->name) ?></li>
<?php endforeach; ?>
</ul>
<?php $this->endCache(); ?>
<?php endif; ?>
Всё, что между beginCache и endCache, будет закешировано на час. При следующем запросе этот блок возьмётся из кеша, и PHP не будет выполняться. Это очень удобно для тяжёлых виджетов.
Зависимости кеша: как не показывать устаревшие данные
Главная проблема кеша — он устаревает. Например, вы закешировали список товаров, а цены изменились. Чтобы не показывать старые данные, используют зависимости. В Yii2 есть несколько типов зависимостей: DbDependency, FileDependency, ExpressionDependency и другие.
Самый частый случай — зависимость от запроса к БД. Пример:
use yii\caching\DbDependency;
$dependency = new DbDependency([
'sql' => 'SELECT MAX(updated_at) FROM product',
]);
$key = 'product_list';
$data = Yii::$app->cache->get($key);
if ($data === false) {
$data = Product::find()->all();
Yii::$app->cache->set($key, $data, 3600, $dependency);
}
return $data;
Здесь кеш будет автоматически инвалидирован, если в таблице product появится запись с более новым updated_at. Удобно, правда? Главное — не забывать обновлять это поле при изменении данных.
Для фрагментов тоже можно указывать зависимости:
$this->beginCache('category_list', [
'duration' => 3600,
'dependency' => new DbDependency(['sql' => 'SELECT MAX(updated_at) FROM category']),
]);
Тегированный кеш: группируем и сбрасываем
Иногда нужно сбросить не весь кеш, а только связанные записи. Например, при обновлении статьи сбросить кеш всех страниц, где она выводится. Для этого используют теги. В Yii2 теги поддерживаются компонентом Cache через методы getOrSet с указанием тегов или через TagDependency.
Пример с TagDependency:
use yii\caching\TagDependency;
$key = 'article_'.$id;
$data = Yii::$app->cache->get($key);
if ($data === false) {
$data = Article::findOne($id);
TagDependency::invalidate(Yii::$app->cache, 'article_'.$id); // сбрасываем старые теги
Yii::$app->cache->set($key, $data, 3600, new TagDependency(['tags' => ['article_'.$id]]));
}
return $data;
При обновлении статьи вы вызываете TagDependency::invalidate(Yii::$app->cache, 'article_'.$id), и все кеши с этим тегом становятся недействительными. Очень гибко.
Практические советы и лайфхаки
- Используйте префиксы для ключей. Например,
'user_'.$id, чтобы избежать коллизий. - Не кешируйте персонализированные данные (корзину, профиль) без привязки к пользователю.
- Для отладки можно временно отключить кеш, установив компоненту
cacheвnullили используяDummyCache. - Очищайте кеш при деплое, если меняется структура данных.
Сравнение типов кеша в Yii2:
| Тип кеша | Когда использовать | Плюсы | Минусы |
|---|---|---|---|
| FileCache | Небольшие проекты, один сервер | Простота, не требует установки | Медленнее, чем память |
| MemCache | Средние и крупные проекты | Быстрый, распределённый | Нужен отдельный сервис |
| Redis | Высоконагруженные проекты | Быстрый, поддерживает теги | Сложнее в настройке |
Что в итоге
Кеширование в Yii2 — это мощный инструмент, который может ускорить сайт в разы. Начните с простых фрагментов и данных, постепенно внедряйте зависимости и теги. Не бойтесь экспериментировать: всегда можно отключить кеш и проверить, как работает без него. Главное — не забывайте сбрасывать кеш при изменении данных, иначе пользователи увидят устаревшую информацию.
Надеюсь, статья была полезной. Удачи в оптимизации!

