cloud-castle / cache
Кэш для PHP 8.1+: PSR-16 и PSR-6 из одного пакета, remember со stampede-защитой (XFetch), теги с O(1)-инвалидацией, пространства имён, цепочки L1/L2, LRU-лимит, нативные счётчики с сохранением TTL, статистика, prune, детерминированный TTL в тестах (PSR-20). Бэкенды: память, файлы с атомарной записью
Requires
- php: >=8.1
- cloud-castle/clock: ^1.0
- cloud-castle/file-system: ^1.0
- cloud-castle/serialize: ^1.1
- psr/cache: ^3.0
- psr/simple-cache: ^3.0
Requires (Dev)
- cloud-castle/memcached: ^1.0
- cloud-castle/redis: ^1.0
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- illuminate/cache: ^10.0
- infection/infection: ^0.29 || ^0.33
- laminas/laminas-cache: ^4.1
- laminas/laminas-cache-storage-adapter-memory: ^3.1
- matthiasmullie/scrapbook: ^1.5
- php-parallel-lint/php-parallel-lint: ^1.4
- phpfastcache/phpfastcache: ^9.2
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- symfony/cache: ^6.4
- tedivm/stash: ^1.2
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
- cloud-castle/memcached: Бэкенд MemcachedStore: ketama-шардирование, SASL, TLS (^1.0)
- cloud-castle/redis: Бэкенд RedisStore: кластер, sentinel, TLS, pipelines (^1.0)
Provides
This package is auto-updated.
Last update: 2026-08-05 06:48:36 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Cache
Кэш для PHP 8.1+, закрывающий PSR-16 и PSR-6 одним пакетом и превосходящий по возможностям сумму популярных аналогов:
rememberсо stampede-защитой (XFetch), теги с O(1)-инвалидацией, изолированные пространства имён, многоуровневые цепочки L1/L2, LRU-лимит памяти, нативные счётчики с сохранением TTL, статистика hits/misses,prune()и детерминированный TTL в тестах через инъектируемые часы (PSR-20). Бэкенды: память, файлы с атомарной записью, Redis и Memcached (клиентыcloud-castle/redisиcloud-castle/memcached); безопасная сериализацияcloud-castle/serialize— белые списки классов и HMAC-подпись записей. И всё это быстрее всех сравниваемых библиотек.
Установка
composer require cloud-castle/cache
Требуется PHP 8.1+. Серверные бэкенды подключаются по потребности:
composer require cloud-castle/redis (RedisStore) и/или
composer require cloud-castle/memcached (MemcachedStore) — ядро пакета
не тянет их в зависимости.
Быстрый старт
<?php
use CloudCastle\Cache\Cache;
// PSR-16 (SimpleCache) в памяти; file('/dir') — на диске с атомарной записью.
$cache = Cache::array();
$cache->set('user.42', $user, 3600);
$user = $cache->get('user.42', $default);
// PSR-6 (CacheItemPool) над тем же бэкендом.
$pool = Cache::filePool('/var/cache/app');
$item = $pool->getItem('report');
if (!$item->isHit()) {
$pool->save($item->set($report)->expiresAfter(600));
}
// Репозиторий: remember + защита от cache stampede (XFetch), счётчики, статистика.
$repo = Cache::repository($cache);
$report = $repo->remember('report', 300, fn () => $api->build(), beta: 1.0);
$repo->increment('report.views'); // TTL записи сохраняется
$ratio = $repo->stats()->hitRatio();
// Теги: O(1)-инвалидация связанных записей без перебора данных.
$cache->tags('users', 'reports')->set('report.42', $report, 3600);
$cache->invalidateTags('users');
// Изолированные пространства имён: свой clear, никаких пересечений.
$sessions = $cache->withNamespace('sessions');
$sessions->clear(); // остальной кэш не тронут
// L1/L2: память перед файлами, найденное проливается вверх.
$fast = Cache::chain([$memoryStore, $fileStore], promoteTtlSeconds: 60);
// Детерминированный TTL в тестах: MockClock вместо реального ожидания.
$cache = Cache::array($mockClock);
// Redis: кластер/sentinel/TLS — в клиенте cloud-castle/redis; TTL исполняет сервер,
// инкременты атомарны между процессами (INCRBY), пространства имён — префиксы.
$redis = Cache::simple(new RedisStore(new \CloudCastle\Redis\Client('redis://127.0.0.1:6379/1')));
// Memcached: шардирование/SASL/TLS — в клиенте cloud-castle/memcached;
// пространства имён — версионные префиксы (очистка одним инкрементом версии).
$memcached = Cache::simple(new MemcachedStore($memcachedClient));
// Строгая десериализация: белый список классов или HMAC-подпись записей.
$audited = Cache::simple(new FileStore('/var/cache/app', $clock, Serializer::php([Report::class])));
Возможности
- PSR-16 + PSR-6 из одного пакета над общим бэкендом (SimpleCache, CacheItemPool).
remember/rememberForeverс вероятностной stampede-защитой XFetch (beta) — толпа запросов не обрушивается на бэкенд в момент истечения (Repository).- Теги с O(1)-инвалидацией по версиям — записи не перебираются (TaggedCache).
- Изолированные пространства имён: свой
clear(), на файлах — подкаталоги (NamespaceCapable). - Многоуровневые цепочки L1/L2 с проливкой найденного вверх (ChainStore).
- LRU-лимит записей в памяти — кэш не разрастается бесконтрольно (ArrayStore).
- Нативные
increment/decrementс сохранением TTL записи (IncrementCapable). pull/add/foreverи статистика hits/misses/writes/deletes из коробки.prune()— целевая уборка просроченного (Pruneable).- Инъектируемые часы (PSR-20): истечение TTL детерминировано в тестах — «перемотка» времени без ожидания.
- Атомарная файловая запись (temp +
rename): конкурентные чтения не видят битых файлов. - Бэкенд Redis (RedisStore) поверх
cloud-castle/redis(кластер, sentinel, TLS): TTL исполняет сервер, инкременты атомарны между процессами, очистка пространства —SCANпо префиксу. - Бэкенд Memcached (MemcachedStore) поверх
cloud-castle/memcached(ketama, SASL, TLS): версионные пространства имён — очистка одним атомарным инкрементом версии, мгновенно видимая всем процессам. - Безопасная сериализация (NativePhpSerializer, SealedSerializer): в файловое и Redis-хранилище инъектируется любой сериализатор
cloud-castle/serialize— белый список классов против POP-цепочек или HMAC-подпись записей против подмены на носителе. - Безопасность по умолчанию: PSR-валидация ключей, SHA-256-имена файлов (без traversal), строгая валидация имён пространств, служебные ключи недостижимы для пользовательских записей.
- Нулевые тяжёлые зависимости — только PSR-контракты и лёгкие
cloud-castle/clock,cloud-castle/file-system,cloud-castle/serialize; клиенты Redis/Memcached — опциональныеsuggest-пакеты.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных
тестов (benchmarks/compare.php) на ОДИНАКОВОЙ операции для всех аналогов,
PHP 8.3.33, без Xdebug.
1. Функциональность
| Возможность | 🏆 CloudCastle | symfony | scrapbook | illuminate | phpfastcache | stash² | laminas | array¹ |
|---|---|---|---|---|---|---|---|---|
| PSR-16 (SimpleCache) из коробки | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| PSR-6 (CacheItemPool) из коробки | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
| Инъектируемые часы (PSR-20) — детерминированный TTL в тестах | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Атомарная файловая запись (temp + rename, без битых кэш-файлов) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| remember / rememberForever (вычислить при промахе) | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| pull / add / forever (высокоуровневые операции) | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Нативный инкремент с сохранением TTL записи | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Теги с O(1)-инвалидацией по версиям | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Изолированные пространства имён (включая изолированный clear) | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Многоуровневая цепочка L1/L2 с проливкой вверх | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| LRU-вытеснение в памяти (лимит записей/байт) | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Stampede-защита из коробки (XFetch/beta/lock) | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Счётчики hits/misses/writes/deletes из коробки | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| prune() — целевая уборка просроченных записей | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Бэкенд Redis из коробки | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Бэкенд Memcached из коробки | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Подключаемая безопасная десериализация (белый список классов, HMAC) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 17 | 13 | 7 | 8 | 6 | 8 | 7 | 0 |
2. Безопасность и корректность
| Свойство | 🏆 CloudCastle | symfony | scrapbook | illuminate | phpfastcache | stash² | laminas | array¹ |
|---|---|---|---|---|---|---|---|---|
| Валидация ключей по PSR (запрет {}()/\@:) | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
| Корректное хранение null (отличается от промаха) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Атомарная запись файлов (нет частичных данных) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Детерминированное истечение TTL (инъектируемые часы) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Устойчивость к битым кэш-файлам (промах вместо падения) | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ |
| Имена файлов — хэш ключа (path traversal исключён) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Строгая валидация имён пространств (защита от ../) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Служебные ключи недостижимы для пользовательских записей | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| HMAC-подпись кэш-нагрузок от подмены на носителе | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Белый список классов при десериализации (анти-POP) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 10 | 6 | 3 | 2 | 4 | 3 | 2 | 0 |
3. Производительность
set + get в кэше «в памяти», 200 000 раз (минимум из 4).
| Решение | Время (мс) | Итог |
|---|---|---|
| array¹ | 6,8 | базовый уровень (не библиотека) |
| 🏆 CloudCastle | 170,3 | быстрейшее среди библиотек |
| illuminate | 220,1 | аналог |
| symfony | 502,6 | аналог |
| scrapbook | 579,6 | аналог |
| phpfastcache | 734,8 | аналог |
| stash² | 1 016,8 | аналог |
| laminas | 1 743,7 | аналог |
4. Потребление памяти
Память самой библиотеки (классы + структуры данных) на 200 000 операций: пик рабочей фазы минус baseline, снятый до создания кэша в изолированном процессе, — стоимость PHP и автолоадера вычтена.
| Решение | Пиковая память (KB) | Итог |
|---|---|---|
| array¹ | 1 | базовый уровень (не библиотека) |
| 🏆 scrapbook | 150 | легчайшее среди библиотек |
| illuminate | 153 | аналог |
| symfony | 186 | аналог |
| CloudCastle | 191 | аналог |
| stash² | 231 | аналог |
| phpfastcache | 931 | аналог |
| laminas | 1 575 | аналог |
5. Утечки памяти
_Рост памяти за 100 000 операций после прогрева и gc_collectcycles (изолированный процесс, только целевая библиотека; 0 — утечек нет).
| Решение | Рост памяти (KB) | Итог |
|---|---|---|
| 🏆 CloudCastle | 0 | без утечек, стабильнее всех |
| symfony | 0 | аналог |
| scrapbook | 0 | аналог |
| illuminate | 0 | аналог |
| phpfastcache | 0 | аналог |
| stash² | 0 | аналог |
| laminas | 0 | аналог |
| array¹ | 0 | базовый уровень (не библиотека) |
6. Качество кода
Машинно-измеримые метрики исходников каждого пакета (жирным — лучшее значение строки).
| Метрика | 🏆 CloudCastle | symfony | scrapbook | illuminate | phpfastcache | stash² | laminas |
|---|---|---|---|---|---|---|---|
| Синтаксические ошибки (phplint) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Файлы со strict_types, % | 100 | 0 | 100 | 0 | 99 | 0 | 19 |
| final-классы, % | 100 | 9 | 0 | 0 | 1 | 0 | 54 |
| Runtime-зависимостей | 5 | 5 | 2 | 4 | 2 | 1 | 7 |
| Файлов исходников | 28 | 88 | 40 | 44 | 142 | 33 | 74 |
| Требование PHP | >=8.1 | >=8.1 | >=8.0.0 | ^8.1 | >=8.0 | ^8.0 | ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 |
| Всего побед | 🏆 4 | 1 | 2 | 1 | 1 | 2 | 1 |
¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов. ² Stash не реализует PSR-16 — выполняется эквивалентная работа его родным PSR-6 пулом (getItem/set/save + getItem/get).
Вывод: CloudCastle Cache — самый быстрый среди сравниваемых библиотек и единственный, кто закрывает весь набор: PSR-16 + PSR-6, remember со stampede-защитой, теги, пространства имён, цепочки, LRU, счётчики, статистику, prune, тестируемый TTL, бэкенды Redis/Memcached и строгую десериализацию — при атомарной файловой записи. По памяти самой библиотеки — компромисс п. «потребление памяти» (см. ограничения ниже): на десятки килобайт тяжелее самого лёгкого аналога, покрывающего в 2–3 раза меньше возможностей.
Честно о плюсах и минусах
Сильные стороны:
- один пакет вместо связки «кэш + хелперы + инвалидация» — суперсет возможностей symfony/illuminate при минимальных зависимостях;
- быстрейший
get/setсреди сравниваемых библиотек; память без утечек (0 KB роста под нагрузкой); - уникально: детерминированный TTL в тестах (PSR-20 часы) и строгая изоляция пространств имён с защитой от path traversal;
- 100 % покрытие строк и MSI 100 % (все мутанты убиты) — поведение зафиксировано тестами полностью.
Ограничения:
- клиенты Redis/Memcached — отдельные пакеты (
suggest, не жёсткие зависимости): для серверных бэкендов доустановитеcloud-castle/redisи/илиcloud-castle/memcached(до их релизов 1.0.0 в require-dev пакета используются dev-срезы); - межпроцессная атомарность
add/incrementна файлах не гарантируется (гонка «оба записали» допустима и задокументирована; на Redis инкремент межпроцессно атомарен нативно, на Memcached — нативная арифметика с клампом декремента на нуле) — для распределённых блокировок нужен внешний lock-механизм; - теги и stampede-мета добавляют по служебной записи — на файловом бэкенде это дополнительные файлы (учитывайте при жёстких лимитах inode);
- память самой библиотеки (классы + структуры) — место в середине таблицы (см. «Потребление памяти» выше): на десятки килобайт тяжелее самого лёгкого аналога (scrapbook) — осознанная цена суперсета возможностей (компромисс допускается приоритетами проекта); стоимость процесса PHP и автолоадера у всех библиотек одинакова.
Где применять:
- Веб-приложения и API (один сервер) — файловый кэш с атомарной записью и тегами: сброс по сущностям без полного flush.
- CLI, воркеры, тесты — кэш в памяти с LRU-лимитом; MockClock делает TTL-сценарии детерминированными.
- Горячие вычисления —
remember(..., beta: 1.0)вместо самодельных блокировок: XFetch размазывает пересчёт по времени. - Микросервисы с локальным L1 —
Cache::chain([память, файлы]): чтения идут из памяти, рестарт переживается за счёт файлового уровня. - Общий кэш нескольких серверов —
RedisStore/MemcachedStore(плюс локальный L1 черезCache::chain([память, Redis])): теги, пространства, счётчики и remember работают поверх серверных бэкендов так же, как поверх файлов. - Кэш на разделяемом/недоверенном носителе —
SealedSerializer(HMAC-подпись) или белый список классов: подменённая запись отвергается и удаляется, а не исполняется.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
composer test:full # phplint → psalm → phpstan → phpmd → phpcs → rector →
# deptrac → мутации → безопасность → память → утечки →
# производительность → качество (гейт превосходства)
composer docs:build # сравнительные бенчмарки + генерация таблиц
Полный список команд с описаниями: composer run-script --list.
Документация
- Репозиторий: https://gitverse.ru/cloud-castle/cache
- Wiki (возможности, примеры, архитектура): wiki/docs/ru
- История изменений: CHANGELOG.md
- Обновление версий: UPGRADING.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano