Класс-сервис для кэширования данных на PHP

09.10.2016 в 16:08
6173
+37

Всем привет, хотел бы поделиться небольшой своей наработкой — классом, который использую в качестве сервиса для кэширования данных в PHP.

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

Для начала сам класс:

class Cache
{
    private $_cachesTTL;
    private $_realTimeStorage = [];
    private $_memcached;

    public function __construct(array $cachesTTL)
    {
        $this->_cachesTTL = $cachesTTL;
        $this->_memcached = new \Memcached();
        $this->_memcached->addServer('localhost', 11211);
    }

    public function set(string $key, $value)
    {
        $this->_realTimeStorage[$key] = $value;

        $ttl = $this->_getTTL($key);
        $this->_memcached->set($key, $value, $ttl);
    }

    public function get(string $key)
    {
        if (isset($this->_realTimeStorage[$key])) {
            return $this->_realTimeStorage[$key];
        }

        return $this->_realTimeStorage[$key] = $this->_memcached->get($key);
    }

    public function invalidate(string $key)
    {
        if (isset($this->_realTimeStorage[$key])) {
            unset($this->_realTimeStorage[$key]);
        }

        $this->_memcached->delete($key);

        return $this;
    }

    private function _getTTL(string $key)
    {
        $prefix = explode(':', $key)[0];

        if (!isset($this->_cachesTTL[$prefix])) {
            return $this->_cachesTTL['default_ttl'];
        }

        return $this->_cachesTTL[$prefix];
    }
}

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

[
    'default_ttl' =>                       60,
    'page' =>                              60*60*24,
    'rubrics' =>                           60*60*24,
    'post' =>                              60,
    'menu' =>                              60*60*24
]

Полный ключ объекта при этом может быть составным и отделяется от основного ключа с помощью двоеточия. Время жизни с помощью метода _getTTL($key) вычисляется по основному ключу. Например, можно сохранять в кэш разные посты, при этом время жизни для них будет одинаковым:

<?php

$cache->set('post:1', $post1);
$cache->set('post:2', $post2);

Метод get($key) возвращает либо существующее значение, либо false. Здесь, как Вы понимаете, имеется ограничение — false мы не кэшируем.

Метод invalidate($key) инвалидирует кэш по нашему запросу. Например, при обновлении какого-то объекта, когда мы не хотим тут же добавлять его в кэш.

Внутри класса есть собственное хранилище, представляющее собой массив. Живет оно в рамках одного запуска приложения. При добавлении в кэш или при извлечении его из объекта в рантайме, оно будет продублировано в это свойство. В случае моего приложения это дало прирост в скорости выполнения в районе 15 процентов. Прежде чем добавлять его себе — проверьте на реальных данных. Если данные нигде не будут использоваться повторно, то этот приём сделает только хуже.

Буду рад узнать о ваших реализациях кэширования в комментариях.

loader
09.10.2016 в 16:08
6173
+37
Комментарии
К этому посту больше нельзя оставлять новые комментарии
Логические задачи с собеседований