Так как в Yii кеширование довольно развито, можно задаться вопросами: "Зачем изобретать велосипед?" и "не проще ли использовать предлагаемые фреймверком решения?". Все это верно, только в том контексте, когда нам нужно простое кеширование. Например, страница одной новости. Но когда у нас большой проект, то при реализации кеширования возникают некоторые трудности.

Допустим, для конкретного товара нужно кешировать его характеристики, фото, обзоры, фильтра, аксессуары. И хочется, чтобы при изменении чего-то одного, обновление кеша не затрагивало остальное (при загрузке дополнительного фото перекеширование характеристик, фильтра, обзоров и аксессуаров нелогично и затратно). Конечно можно добавить в кеш каждый компонент отдельно и не связывать его с товаром. Но тогда мы сталкиваемся с проблемой размножения мелких компонентов, принадлежащих к одному объекту и никак несвязанных. И в случае удаления товара, сброс кеша для всех этих компонентов будет занимать дополнительные ресурсы сервера из-за того, что сначала нужно найти их связь с товаром. Опять же, можно где-то хранить массив связей товара с его компонентами (в том же кеше под определенным id). Тогда получается не только лишний посредник, но и не совсем истетическое решение проблемы. Более простой и изящный способ - это кеширование по тегам, где записи кеша будут зависить от тега (например, продукт) или группы тегов. Именно такое решение я и представлю ниже.

Для начала создадим компонент (components/TagDependency.php):

class TagDependency implements ICacheDependency
{

    const PREFIX = '___tag___';

    /**
     * Временная метка.
     * 
     * @var integer 
     */
    protected $timestamp;

    /**
     * Список тегов.
     *
     * @var array 
     */
    protected $tags;

    /**
     * @param string|array $tags
     */
    public function __construct($tags)
    {
        $this->tags = (array) $tags;
    }

    public function evaluateDependency()
    {
        $this->timestamp = time();
        return true;
    }

    public function getHasChanged()
    {
        $tags = array_map(create_function('$e', 'return TagDependency::PREFIX . $e;'), $this->tags);

        $tagsTime = Yii::app()->cache->mget($tags);

        foreach ($tagsTime as $time)
            if ($time >= $this->timestamp)
                return true;

        return false;
    }

}

Далее для удобства создаем хелпер (helpers/CacheHelper.php):

class CacheHelper
{

    /**
     * Обновляем время у тегов делая кеш невалидным.
     * 
     * @param string|array $tags
     */
    static public function clearTags($tags)
    {
        foreach ((array) $tags as $tag)
            Yii::app()->cache->set(TagDependency::PREFIX . $tag, time());
    }

    /**
     * Удаляем теги.
     * 
     * @param string|array $tags
     */
    static public function deleteTags($tags)
    {
        foreach ((array) $tags as $tag)
            Yii::app()->cache->delete(TagDependency::PREFIX . $tag);
    }

}

Теперь давайте посмотрим на результат нашей работы:

// Возьмем текущий класс через который осуществляется кеширование
$cache = Yii::app()->cache;

// Сохраним фильтра категории1 в кеш с указанием зависимостей от тегов
$cache->set('category.1.filters', 'data', 0, new TagDependency(array('product-1', 'product-2')));

// Смотрим, что запись в кеше имеется
var_dump($cache->get('category.1.filters')); // data

// Сохраним фото товара1 в кеш с указанием зависимости от товара1
$cache->set('product.1.fotos', 'product-1-fotos-data', 0, new TagDependency('product-1'));

// Смотрим, что запись в кеше имеется
var_dump($cache->get('product.1.fotos')); // product-1-fotos-data

// Сохраним фильтра товара1 в кеш с указанием зависимости от товара1
$cache->set('product.1.filters', 'product-1-filters-data', 0, new TagDependency('product-1'));

// Смотрим, что запись в кеше имеется
var_dump($cache->get('product.1.filters')); // product-1-filters-data

// Сохраним фото товара2 в кеш с указанием зависимости от товара2
$cache->set('product.2.fotos', 'product-2-fotos-data', 0, new TagDependency('product-2'));

// Смотрим, что запись в кеше имеется
var_dump($cache->get('product.2.fotos')); // product-2-fotos-data

// Ждем секундочку..
sleep(1);

// Сбрасываем кеш для тега `product-1`
CacheHelper::clearTags('product-1');

// Т.к. фильтра категории1, фото и фильтр продукта1 
// зависят от тега `product-1`, то при очистке тега 
// их тоже не будет существовать
var_dump($cache->get('product.1')); // false
var_dump($cache->get('category.1.filters')); // false
var_dump($cache->get('product.1.fotos')); // false
var_dump($cache->get('product.1.filters')); // false

// просто для наглядности, проверим, что 
// фото товара2 еще в кеше
var_dump($cache->get('product.2.fotos')); // product-2-fotos-data

// удалим теги
CacheHelper::deleteTags(array('product-1', 'product-2'));

Таким образом у нас получилось построить зависимость фильтров и фотографий от товара. Конечно же можно использовать не только связку товар-компоненты товара, но и любые другие связи. И независимо от того, что мы добавим в кеш, записи будут храниться структуировано и логично. А удаление всех зависимостей будет занимать одну строчку кода.