Что такое кэш? Основы. На примере 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 путями:
- Создать константу (аналогичную
SAVE_DIR
, и указать время жизни кэша), напримерconst EXPIRIES = 24 * 60 * 60
, что значит, что кэш будет действителен 24 часа. И в дальнейшем сохранять все файлы с использованием этой константы. - Или можно добавить возможность задавать время жизни кэша, при вызове метода
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, эта технология, которая активно используется в веб разработке, и успешно решает актуальные проблемы программистов.