Продвинутое

Кеширование

Кеш в Winter — это пакет winter-cache: пуловый доступ к Redis через класс-хранилище. Вы описываете RedisConfig (из .env) и класс-Store поверх RedisStore, который отдаёт готовый \Redis-хендл — дальше используете нативные команды Redis.

Пакет winter-cacheБэкенд Redis (пул)База RedisStore

Что такое кеширование и зачем

Кеширование — хранение результата дорогой операции, чтобы не пересчитывать его заново.

Проблема. Тяжёлые запросы к БД, внешние API, вычисления — если делать их на каждый запрос, растут задержка и нагрузка. Данные, которые меняются редко, незачем доставать каждый раз.

Решение. Кладите результат в быстрое key-value хранилище (Redis) с TTL и берите из него, пока не устарел. Winter даёт пуловый доступ к Redis через класс-хранилище. Об этом и раздел.

Настройка подключения

Сгенерируйте конфиг Redis (флаг -R) — он читает REDIS_* из .env:

bash
php call make -R .Main   # → main/MainRedisConfig.php
main/MainRedisConfig.php
<?php

namespace Main;

use Flytachi\Winter\Cache\Config\RedisConfig;

class MainRedisConfig extends RedisConfig
{
  public function setUp(): void
  {
      $this->host          = env('REDIS_HOST', 'localhost');
      $this->port          = env('REDIS_PORT', 6379);
      $this->password      = env('REDIS_PASS', '');
      $this->databaseIndex = env('REDIS_DBNAME', 0);
  }
}

Класс-хранилище

Сгенерируйте Store (флаг -t) — он наследует RedisStore, указывает конфиг и отдаёт пуловое подключение \Redis:

bash
php call make -t .Session   # → main/SessionStore.php
main/SessionStore.php
<?php

namespace Main;

use Flytachi\Winter\Cache\Store\RedisStore;

class SessionStore extends RedisStore
{
  protected static string $redisConfigClassName = MainRedisConfig::class;

  public static function main(): \Redis
  {
      return self::init(0);   // подключение на индексе БД 0
  }
}

Метод-аксессор (main() здесь) возвращает \Redis из пула — дальше вызываете нативные команды Redis.

Использование

php
$redis = SessionStore::main();

// Записать с TTL 1 час:
$redis->setex('user:42:profile', 3600, json_encode($profile));

// Прочитать:
$cached = $redis->get('user:42:profile');

// Паттерн cache-aside:
$profile = $redis->get($key);
if ($profile === false) {
  $profile = $this->service->buildProfile(42);   // дорого
  $redis->setex($key, 3600, json_encode($profile));
} else {
  $profile = json_decode($profile, true);
}

Пул соединений

RedisStore::init() берёт подключение из ConnectionPool — под FPM это синглтон на воркер, под Swoole корутинный пул. Соединение не открывается на каждый вызов.

Файловая альтернатива

Когда Redis не нужен (токены, троттлинг, мелкие кеши), подойдёт файловое хранилище с TTL — см. Файловое хранилище.

Дальше