Что такое кэш? Основы. На примере php-класса

Что такое кэш? Основы. На примере php-класса

Кэширование - это важная ступень оптимизации вашего приложения. Кэш - это промежуточное сохранение данных в более быстрое хранилище, чем выборка исходных данных, или их расчёт. Наиболее вероятные для запроса данные - всегда должны быть закэшированы. И сегодня, на примере простого PHP-класса, мы рассмотрим, как написать простой класс кэширования.

Если в рамках вашего проекта сторонние библиотеки не применимы, или вы просто хотите понять, как работает кэш, и что такое серверное кэширование сайта, то эта статья для вас. Вы, так же можете почитать о том что такое Redis, и как можно кэшировать данные с его помощью. А в текущей статье, мы напишем небольшой php класс для кэширования данных.

Техническая реализация

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

interface CacheInterface
{
    public static function get($key);
    public static function set($key, $value);
    public static function delete($key);
}

Здесь все методы являются статическими, для удобства вызова и демонстрации, например, Cache::get('article-1')

Итого, этот интерфейс говорит нам о том, что нужно реализовать 3 основных метода: get, set, delete.

Реализацию можно написать таким образом:

Я буду сохранять кэш в json-формате, потому входяными данными должен быть массив

Class Cache implements CacheInterface {
    const SAVE_DIR = './storage/cache'; //папка в которую сохраняем кэш

    public static function get($key)
    {
        $filePath = self::SAVE_DIR . "/{$key}.json";

        if(self::exists($key)) {
            return file_get_contents(json_decode($filePath, true));
        }

        return null;
    }

    public static function set($key, $value)
    {
        $filePath = self::SAVE_DIR . "/{$key}.json";

        return file_put_contents($filePath, json_encode($value));
    }

    public static function delete($key)
    {
        if(self::exists($key)) {
            $filePath = self::SAVE_DIR . "/{$key}.json";

            unlink($filePath);
        }

        return true;
    }

    private static function exists($key)
    {
        $filePath = self::SAVE_DIR . "/{$key}.json";
        if(file_exists($filePath)) {
            return true;
        }

        return false;
    }
}

Теперь, по порядку:
константа SAVE_DIR указывает на папку, в которую сохраняется кэш. Я пользуюсь относительным путём, однако, лучше в своём коде определить константу, и прописывать полный путь к папке, типа ROOT_PATH . '/storage/cache'

GET - получение данных

Первым реализован метод get, который получает кэш по ключу. К примеру, мы сохраняем кэш статьи, и у каждой статьи будет свой отдельный кэш, по уникальному ключу: article1, article2 и т.д.
Что, в вашем коде будет вызываться, как: Cache::get('article1), Cache::get('article2')
И, так как я писал, что данные буду хранить в формате json, то и файл буду именовать соответственно.

Так же, проверка на существование файла была вынесена в метод exists, для удобства, но его разберём ниже.

SET - запись данных

Этот метод сохраняет данные по ключу, и перезаписывает, если ключ уже существует.
Вызывается в коде: Cache::set('article1', [...]), с каким-то массивом данных.
Здесь не понадобилась проверка на существование файла, так как file_put_contents сам перезапишет всё содержиое файла на новое, и без нашей помощи.

DELETE - удаление данных

Метод delete - удаляет данные из кэша, и возвращает результат удаление (true / false).

EXISTS - метод проверки существования кэша

Этот метод проверяет, существует ли кэш с этим ключом (true / false).

Что мы имеем?

Итого, мы имеем класс кэширования, который реализует 3 основных метода - get, set, delete. И теперь, мы, из своего кода можем управлять кэшем.
Однако, можно ещё модифицировать этот класс, и добавить функцию времени жизни кэша.

Здесь можно пойти 2 путями:

  1. Создать константу (аналогичную SAVE_DIR, и указать время жизни кэша), например const EXPIRIES = 24 * 60 * 60, что значит, что кэш будет действителен 24 часа. И в дальнейшем сохранять все файлы с использованием этой константы.
  2. Или можно добавить возможность задавать время жизни кэша, при вызове метода SET, что позволит уникально задавать кэш разным сущностям.

Я реализую второй вариант. Потому, нужно модифицировать методы get, в котором нужно добавить механизм проверки срока действия кэша, и метод set - где нужно реализовать добавление срока действия в файл кэша.

Новый метод GET будет выглядеть:

public static function get($key)
{
    $filePath = self::SAVE_DIR . "/{$key}.json";

    //если кэш существует, и срок его не истёк
    if(self::exists($key) && !self::expired($key)) {
        return file_get_contents(json_decode($filePath, true));
    }

    return null;
}

Новый метод SET будет выглядеть:

public static function set($key, $value = 365 * 24 * 60 * 60)
{
    $filePath = self::SAVE_DIR . "/{$key}.json";

    $value['expires'] = time() + $value;

    return file_put_contents($filePath, json_encode($value));
}

И теперь, вызов этого метода будет выглядеть: Cache::set('key', [...], 10 * 60 * 60), или Cache::set('key', [...]) в результате чего, значение срока жизни кэша будет установлено по умолчанию - в один год.

Время действия кэша указывается в секундах

Для удобства, я добавил новый метод expired, который будет проверять, актуален ли ещё этот кэш.

private static function expired($key) {
    $filePath = self::SAVE_DIR . "/{$key}.json";

    $data = file_get_contents(json_decode($filePath, true));

    if($data['expires'] >= time()) {
        return false;
    }

    self::delete($key);
    return true;
}

Метод expired возвращает true / false, истёк ли уже срок его действия. И, в случае, если истёк, но файл существует, то удаляем его.

Резюме

Здесь была описана простая схема работы кэша, и реализация на примере PHP-класса. Это простая реализация, но благодаря ей вы поймёте, как устроен механизм кэширования в более сложных вариантах исполнения. Надеюсь, что я ответил на вопрос, как кэшировать данные в php.

Как рекомендовалось ранее, советую прочитать статью об Redis, эта технология, которая активно используется в веб разработке, и успешно решает актуальные проблемы программистов.