Arris µFramework Cache Engine.
Кэш-движок Arris: статический фасад Cache — репозиторий вычисленных значений в памяти + опциональное зеркало в Redis.
Redis (через karelwintersky/arris.toolkit.nanoredis) — слой персистентности: при подключении значения берутся из / сохраняются в него; при отсутствии подключения значения просто живут в ключах репозитория. Репозиторий — это и есть кэш; Redis необязателен.
composer require karelwintersky/arris.cacheТребования: PHP ^8.2, ext-redis, ext-pdo, ext-json, ext-mbstring.
use Arris\Cache\Cache;
// PDO-подключение (опционально, нужно только для RULE_SOURCE_SQL)
$pdo = (new \Arris\Database\Config())
->setUsername('root')
->setPassword('password')
->setDatabase('testdatabase')
->connect();
// Редис выключен — значения живут только в репозитории
Cache::init(redis_enabled: false, PDO: $pdo);
// Редис включён — значения хранятся в редисе и зеркалятся в репозиторий
Cache::init(
redis_host: '127.0.0.1',
redis_port: 6379,
redis_database: 0,
redis_enabled: true,
PDO: $pdo
);
// SQL-источник
Cache::addRule(
'districts',
source: Cache::RULE_SOURCE_SQL,
action: 'SELECT id, name FROM districts WHERE hidden = 0 ORDER BY id ASC',
ttl: Cache::TIME_FULL_DAY
);
// Коллбэк
Cache::addRule(
'data',
source: Cache::RULE_SOURCE_CALLBACK,
action: static fn() => 5,
);
Cache::addRule(
'callback',
source: Cache::RULE_SOURCE_CALLBACK,
action: [ "TestClass@getData", [ 1000000 ] ]
);
// Сырое значение
Cache::addRule(
'raw',
source: Cache::RULE_SOURCE_RAW,
action: [ 1 => 2, 3 => "b" ]
);
$districts = Cache::get('districts');Правила: Cache::addRule($rule_name, $enabled = true, $source = '', $action = null, $ttl = 0): Result
- Если Redis подключён и ключ существует — значение берётся из Redis и кладётся в репозиторий (его TTL продолжает жить в Redis).
- Иначе значение вычисляется по источнику:
RULE_SOURCE_SQL('sql') —$pdo->query($action)->fetchAll();PDOExceptionоборачивается вCacheDatabaseException;RULE_SOURCE_CALLBACK('callback') — вызов коллбэка;RULE_SOURCE_RAW('raw') — значение as-is.
- Результат попадает в репозиторий и зеркалится в Redis с
$ttl(0 — вечно). Значения в Redis хранятся в JSON.
Коллбэк может быть:
- instance of
Closure Class@method— динамический вызов метода экземпляраClass::method— статический вызовcustomFunction- массив
[handler, params]— параметры передаются всегда массивом;handlerможет быть строкой илиClosure
Cache::set(string $key, $data): void // записать значение
Cache::get(string $key, $default = null): mixed // прочитать (или $default)
Cache::check(string $key): bool // есть ли ключ
Cache::unset(string $key): void // удалить из репозитория
Cache::drop(string $key, bool $redis_update = true): Result // удалить из репозитория (+ Redis)
Cache::dropAll(bool $redis_update = true): Result // очистить всё (+ Redis)Cache::redisFetch(string $key, bool $use_json_decode = true): mixed // прочитать (JSON-декод)
Cache::redisPush(string $key, $data, int $ttl = 0, bool $use_json_encode = true): Result // записать только в Redis
Cache::push(string $key, $data, int $ttl = 0, bool $use_json_encode = true): Result // в репозиторий И Redis
Cache::redisDel(string $key): Result // удалить (допустима маска, напр. 'article*'); список удалённых ключей — в $result->raw_array
Cache::redisCheck(string $key): bool // есть ли ключ в Redis
Cache::redis()->fetch(...) // хелпер, аналог redisFetch
Cache::redis()->push(...) // хелпер, аналог redisPush
Cache::redis()->del(...) // хелпер, аналог redisDel
Cache::redis()->check(...) // хелпер, аналог redisCheck
Cache::redis()->keys(string $pattern = '*'): array
Cache::getConnector(): RedisClient // прямой коннектор (Arris\Toolkit\RedisClient)Cache::addCounter(string $key, int $initial = 0, int $ttl = 0): int
Cache::incrCounter(string $key, int $diff = 1): int
Cache::decrCounter(string $key, int $diff = 1): int
Cache::getCounter(string $key, int $default = 0): intКогда Redis подключён — он является источником результата (incrBy/decrBy), репозиторий зеркалит значение. Без Redis счётчики живут только в репозитории.
Методы-действия возвращают Arris\Entity\Result (karelwintersky/arris.entity):
init, addRule, drop, dropAll, push, redisPush, redisDel.
Проверка результата:
$result = Cache::drop('key');
if ($result->is_success) {
echo $result->getMessage();
}| Константа | Значение | Комментарий |
|---|---|---|
TIME_SECOND |
1 | |
TIME_MINUTE |
60 | |
TIME_HOUR |
3600 | |
TIME_DAY |
43200 | «день» = 12 часов |
TIME_FULL_DAY |
86400 | «сутки» = 24 часа |
TIME_MONTH |
2592000 | |
TIME_YEAR |
31104000 |
searchHashLike($source, $field, $pattern, $case_sensitive)— фильтр строк 2D-массива по подстроке в колонке;searchHashAsKeyValue($array, $key, $value, $strict)— найти подмассив по значению колонки;sortHashBySubkey($dataset, $order_by, $strict)— usort по ключу подмассива;raiseFlag($flag, $value, $ttl)— тонкая обёртка надredisPush;jsonize($data)—json_encode(UNICODE | PRESERVE_ZERO_FRACTION | INVALID_UTF8_SUBSTITUTE | THROW_ON_ERROR);overrideDefaults($defaults, $options)— дефолты, перезаписанные опциями;fetchOptionBool($option, $if_present, $if_not_present_or_zero)— чтение 0/1-флага из Redis;compileCallbackHandler($actor, $logger)— компиляция коллбэка в[callable, params].
Arris\Cache\Exceptions\CacheCallbackException— неверный коллбэк в правиле;Arris\Cache\Exceptions\CacheDatabaseException—PDOException, обёрнутый в правиле.
composer install
vendor/bin/phpunit77 тестов / 183 assertions (phpunit ^10.5). Redis-тесты работают в изолированной БД 15 и автоматически пропускаются, если Redis недоступен — набор проходит и без Redis. SQL-тесты используют SQLite :memory:, MySQL не требуется.
- нужен ли кастомный декодер json?
- сделать алиас
flush()как аналогdrop()