cloud-castle / memcached
Клиент Memcached для PHP 8.1+ на чистом PHP без расширений: текстовый, бинарный и meta-протокол, ketama-шардирование с failover, пул соединений, SASL и TLS, PSR-6 и PSR-16, теги, компрессия, CAS, счётчики, метрики, встроенный тестовый сервер.
Requires
- php: >=8.1
- cloud-castle/serialize: ^1.1
- psr/cache: ^3.0
- psr/clock: ^1.0
- psr/simple-cache: ^3.0
Requires (Dev)
- 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-memcached: ^3.0
- matthiasmullie/scrapbook: ^1.5
- memcachier/php-memcache-sasl: ^1.0
- 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
- ext-igbinary: Компактная бинарная сериализация значений (быстрее и меньше, чем serialize)
- ext-lz4: Сверхбыстрое сжатие значений с минимальной задержкой
- ext-msgpack: Кроссязычная бинарная сериализация значений (MessagePack)
- ext-openssl: TLS-соединения с Memcached 1.6+ (--enable-ssl)
- ext-zlib: Сжатие значений алгоритмами deflate/gzip без внешних зависимостей
- ext-zstd: Сжатие значений с лучшим соотношением размер/скорость
This package is auto-updated.
Last update: 2026-07-31 06:19:22 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Memcached
Клиент Memcached для PHP 8.1+ на чистом PHP — без ext-memcached и ext-memcache.
Packagist
Репозиторий
Качество кода
Зачем он нужен
Штатный способ работать с Memcached из PHP — расширение ext-memcached поверх
libmemcached. Оно быстрое, но его нужно собирать под каждую версию PHP, и на
управляемом хостинге или в чужом контейнере его может просто не быть.
Этот пакет реализует протокол Memcached на PHP: composer require — и клиент
работает. Заодно становятся возможными вещи, которых расширение не даёт:
подпись значений против подмены, meta-команды Memcached 1.6+ и тестовый сервер
внутри процесса.
Установка
composer require cloud-castle/memcached
Требуется PHP 8.1+. Расширения не обязательны: igbinary, msgpack,
zstd, lz4 подключаются автоматически, если собраны. Если собрано
ext-memcached, клиент может работать через него — см. «Выбор бэкенда».
Быстрый старт
use CloudCastle\Memcached\Client;
use CloudCastle\Memcached\Configuration\{Config, Server};
$client = new Client(new Config([new Server('127.0.0.1', 11211)]));
$client->set('user:1', ['name' => 'Иван'], 300);
$user = $client->get('user:1');
// Значение возвращается того же типа, каким было записано:
// false не превратится в пустую строку, а записанный null отличим от промаха.
$client->set('flag', false);
var_dump($client->get('flag')); // bool(false)
var_dump($client->has('flag')); // bool(true)
Вычислить значение при промахе:
$report = $client->remember('report:2026-07', fn () => buildHeavyReport(), 3600);
Кластер с весами и переключением при отказе:
$client = new Client(new Config([
new Server('10.0.0.1', 11211, weight: 2, alias: 'node-1'),
new Server('10.0.0.2', 11211, weight: 1, alias: 'node-2'),
]));
Интеграция по стандартам PSR
Код, написанный под Psr\SimpleCache\CacheInterface или
Psr\Cache\CacheItemPoolInterface, работает с этим клиентом без правок:
use CloudCastle\Memcached\Psr\{CacheItemPool, SimpleCache};
$psr16 = new SimpleCache($client);
$psr16->set('ключ', $value, 300);
$psr6 = new CacheItemPool($client);
$item = $psr6->getItem('ключ');
if (!$item->isHit()) {
$item->set(buildValue())->expiresAfter(300);
$psr6->save($item);
}
Разница между стандартами стоит того, чтобы её знать: PSR-16 не отличает
записанный null от промаха, а PSR-6 отличает — через isHit(). Родной
API клиента различает всегда, поэтому там, где кэшируются отрицательные
ответы, лучше использовать его напрямую.
Выбор бэкенда
Операции выполняет один из двух исполнителей: собственная реализация
протокола на PHP либо расширение ext-memcached поверх libmemcached.
use CloudCastle\Memcached\Configuration\{Backend, Config, Server, Topology};
// Расширение, если оно собрано; иначе — чистый PHP. Одна сборка
// приложения работает и на боевом сервере, и на управляемом хостинге.
$client = new Client(new Config(
[new Server('127.0.0.1', 11211)],
topology: new Topology(backend: Backend::Auto),
));
Что выбрать — зависит от нагрузки, и цифры честные:
| Нагрузка | Чистый PHP | libmemcached |
|---|---|---|
5000 циклов set + get | 1239 мс | 1411 мс |
| 500 пакетов по 100 ключей | 453 мс | 176 мс |
На одиночных операциях быстрее собственный протокол: getMulti с
CAS-токенами обходится дороже, чем один кадр meta. На пакетном чтении
втрое выигрывает расширение — сотню ответов оно разбирает в C, а не в PHP.
Записи бэкенда libmemcached побайтово совместимы с symfony/cache и
другими обёртками над расширением: сериализация оставлена самому
расширению. Обратная сторона — формат отличается от собственного кодека
пакета, поэтому смена бэкенда требует прогрева кэша. Подпись значений и
meta-команды на этом бэкенде недоступны: расширение их не поддерживает.
Возможности
Каждая возможность описана отдельной страницей wiki с примерами и сравнением с аналогами.
| Возможность | Что даёт |
|---|---|
| Два бэкенда | чистый PHP или libmemcached, с автовыбором по окружению |
| Три диалекта протокола | текстовый, бинарный и meta-команды Memcached 1.6+ |
| Meta-команды | значение, TTL и версия CAS за одно обращение |
| Кластер и ketama | консистентное хеширование, совместимое с libmemcached |
| Отказоустойчивость | переключение на живой узел и карантин упавших |
| Сериализация | PHP, JSON, igbinary, MessagePack + белый список классов |
| Сжатие | deflate, gzip, zstd, lz4 с порогом и проверкой выгоды |
| Подпись значений | HMAC против подмены записи в кэше |
| Безопасность | защита от инъекции команд, SASL, TLS |
| Счётчики и CAS | атомарные операции на стороне сервера |
| Тестовый сервер | тесты без сети и без запуска memcached |
| Метрики | попадания, промахи и здоровье узлов |
| PSR-16 и PSR-6 | интеграция с фреймворками без правок кода |
Сравнение с аналогами
Все таблицы ниже и бейджи качества выше генерируются автоматически из
замеров и отчётов инструментов: composer docs:build. Ни одна цифра не
написана руками — зашитое в разметку число устаревает после первого же
добавленного теста и начинает врать читателю.
Функциональность
| Возможность | CloudCastle | symfony | illuminate | scrapbook | phpfastcache | stash | laminas | ext-memcached¹ |
|---|---|---|---|---|---|---|---|---|
| Работает без расширений PHP (чистый PHP) | ✅ | — | — | — | — | — | — | — |
| PSR-16 (SimpleCache) из коробки | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | — |
| PSR-6 (CacheItemPool) из коробки | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | — |
| Выбор бэкенда: чистый PHP или libmemcached | ✅ | — | — | — | — | — | — | — |
| Автовыбор бэкенда по наличию расширения | ✅ | — | — | — | — | — | — | — |
| Текстовый протокол | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Бинарный протокол | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Meta-команды Memcached 1.6+ | ✅ | — | — | — | — | — | — | — |
| Чтение TTL и CAS одним запросом | ✅ | — | — | — | — | — | — | — |
| Консистентное хеширование ketama | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Автоматическое переключение при отказе узла | ✅ | — | — | — | — | — | — | ✅ |
| Карантин упавших узлов | ✅ | — | — | — | — | — | — | — |
| SASL-аутентификация | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| TLS-соединение | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| UNIX-сокеты | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Оптимистическая блокировка (CAS) | ✅ | — | — | ✅ | — | — | ✅ | ✅ |
| Атомарные счётчики с созданием при промахе | ✅ | — | — | — | — | — | — | ✅ |
| append / prepend без чтения значения | ✅ | — | — | — | — | — | — | ✅ |
| Подпись значений (HMAC) против подмены | ✅ | — | — | — | — | — | — | — |
| Белый список классов при восстановлении | ✅ | ✅ | — | — | — | — | — | — |
| Выбор формата сериализации (4 формата) | ✅ | ✅ | — | — | ✅ | — | ✅ | ✅ |
| Выбор алгоритма сжатия (4 алгоритма) | ✅ | ✅ | — | — | — | — | ✅ | ✅ |
| Встроенный тестовый сервер без сети | ✅ | — | — | — | — | — | — | — |
| Инъектируемые часы (детерминированный TTL) | ✅ | ✅ | — | — | — | — | — | — |
| Счётчики попаданий и промахов клиента | ✅ | — | — | — | ✅ | — | — | — |
| Итого возможностей | 25 | 12 | 7 | 9 | 10 | 4 | 11 | 12 |
| 🏆 Победитель | 🏆 | |||||||
Безопасность
| Механизм защиты | CloudCastle | symfony | illuminate | scrapbook | phpfastcache | stash | laminas | ext-memcached¹ |
|---|---|---|---|---|---|---|---|---|
| Отказ на управляющие символы в ключе (инъекция команды) | ✅ | ✅ | — | ✅ | ✅ | — | ✅ | ✅ |
| Ключ не обрезается молча при превышении длины | ✅ | ✅ | — | — | — | — | — | — |
| Белый список классов при восстановлении значения | ✅ | — | — | — | — | — | — | — |
| Лимит длины нагрузки при разборе (защита от исчерпания памяти) | ✅ | — | — | — | — | — | — | — |
| Подпись значений HMAC с обнаружением подмены | ✅ | — | — | — | — | — | — | — |
| Строгий режим: неподписанная запись отвергается | ✅ | — | — | — | — | — | — | — |
| TLS с полной проверкой сертификата по умолчанию | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Пароль SASL не попадает в дампы и трассировки | ✅ | — | — | — | — | — | — | — |
| Учётные данные не сериализуются | ✅ | — | — | — | — | — | — | — |
| Fail-safe: отказ узла не выдаётся за промах кэша | ✅ | — | — | — | — | — | — | — |
| Итого возможностей | 10 | 3 | 1 | 2 | 2 | 0 | 2 | 2 |
| 🏆 Победитель | 🏆 | |||||||
Производительность
set + get на общем сервере Memcached, 20 000 раз (минимум из 3).
| Пакет | Время | 🏆 Победитель |
|---|---|---|
| ext-memcached¹ (базовый уровень) | 3 972.4 мс | |
| illuminate | 4 649.4 мс | 🏆 |
| phpfastcache | 5 213.5 мс | |
| scrapbook | 5 286.4 мс | |
| symfony | 5 822.3 мс | |
| stash | 9 082.3 мс | |
| laminas | 9 388.1 мс | |
| CloudCastle | 10 271.6 мс | |
Потребление памяти
Память самой библиотеки (классы + структуры данных): пик рабочей фазы минус baseline, снятый до создания клиента в изолированном процессе, — стоимость PHP и автолоадера вычтена.
| Пакет | Память | 🏆 Победитель |
|---|---|---|
| ext-memcached¹ (базовый уровень) | 1 KB | |
| scrapbook | 96 KB | 🏆 |
| illuminate | 188 KB | |
| stash | 396 KB | |
| symfony | 431 KB | |
| CloudCastle | 695 KB | |
| laminas | 1 396 KB | |
| phpfastcache | 2 772 KB | |
Утечки памяти
_Рост памяти за 20 000 операций после прогрева и gc_collectcycles (изолированный процесс, только целевая библиотека; 0 — утечек нет).
| Пакет | Рост | 🏆 Победитель |
|---|---|---|
| stash | -17 KB | 🏆 |
| CloudCastle | 0 KB | |
| symfony | 0 KB | |
| illuminate | 0 KB | |
| scrapbook | 0 KB | |
| phpfastcache | 0 KB | |
| laminas | 0 KB | |
| ext-memcached¹ (базовый уровень) | 0 KB | |
Качество кода
| Метрика | CloudCastle | symfony | illuminate | scrapbook | phpfastcache | stash | laminas | 🏆 Победитель |
|---|---|---|---|---|---|---|---|---|
| Синтаксические ошибки (phplint) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | CloudCastle, symfony, illuminate, scrapbook, phpfastcache, stash, laminas 🏆 |
| Файлы со strict_types, % | 100 | 0 | 0 | 100 | 99 | 0 | 19 | CloudCastle, scrapbook 🏆 |
| final-классы, % | 100 | 9 | 0 | 0 | 1 | 0 | 54 | CloudCastle 🏆 |
| Runtime-зависимостей | 4 | 5 | 4 | 2 | 2 | 1 | 7 | stash 🏆 |
| Файлов исходников | 93 | 89 | 44 | 40 | 142 | 33 | 74 | stash 🏆 |
| Минимальная версия PHP | >=8.1 | >=8.1 | ^8.1 | >=8.0.0 | >=8.0 | ^8.0 | ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 | — |
¹ Базовый уровень: расширение на C, не composer-библиотека. Показано для контекста и не претендует на победу среди PHP-пакетов.
Возможности проверены по исходникам и документации пакетов. Отметка «есть» ставится и тогда, когда возможность приходит из расширения под пакетом: пользователю она доступна.
Замер выполнен 2026-07-30 на PHP 8.1.34.
Честно о плюсах и минусах
Плюсы
- Работает без расширений:
composer require— и всё, никакой пересборки PHP. - Функционально шире любого аналога: meta-команды, подпись значений, карантин узлов, встроенный тестовый сервер — этого нет ни у одного из сравниваемых.
- Два бэкенда под одним API: без расширения работает чистый PHP, с расширением — libmemcached, и пакетное чтение ускоряется втрое.
- Стандарты PSR-16 и PSR-6 из коробки — пакет встаёт в любой фреймворк без переписывания прикладного кода.
- Безопасность заложена в поведение: инъекция команды через ключ невозможна, восстановление объектов ограничено белым списком, отказ узла не выдаётся за промах кэша.
- Тестируемость: клиент проверяется целиком, включая обрывы связи и повреждённые ответы, без поднятия сервера.
Минусы
- На пакетных операциях чистый PHP уступает расширению втрое. Разбор сотни ответов в PHP объективно медленнее, чем в C. Лечится переключением на бэкенд libmemcached там, где расширение доступно, — но тогда теряются подпись значений и meta-команды.
- Памяти на процесс тратится больше, чем у обёрток над расширением: структуры протокола живут в PHP, а не в C.
- Подпись значений несовместима с серверными счётчиками: подписанное число сервер не умеет инкрементировать.
Когда его стоит брать
Берите, если:
- расширение
ext-memcachedнедоступно или его установка — отдельная боль (управляемый хостинг, чужой контейнер, быстрый прототип); - в кэше лежат данные, подмена которых опасна: права доступа, результаты проверок, флаги доступности — тогда подпись значений окупает всё;
- нужны meta-команды Memcached 1.6+: чтение значения вместе с остатком TTL экономит целый цикл запросов при досрочном продлении;
- важна тестируемость кэширующего слоя без инфраструктуры в CI;
- кластер меняет состав, и нужен предсказуемый перенос ключей плюс карантин отказавших узлов.
Не берите, если:
- узкое место — именно скорость обращений к кэшу, расширение уже установлено,
и никакой дополнительный функционал не нужен: тогда
ext-memcachedнапрямую или тонкая обёртка над ним будут быстрее; - нужен только PSR-16 поверх нескольких бэкендов сразу — для этого лучше подходит cloud-castle/cache.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer test:full # полный порядок проверок качества
composer docs:build # перегенерировать сравнительные таблицы и бейджи
Интеграционные тесты требуют сервер; адрес задаётся через MEMCACHED_HOST
и MEMCACHED_PORT. Без сервера они помечаются пропущенными, а не «зелёными».
docker run -d --name memcached -p 11211:11211 memcached:1.6-alpine
Документация
- Wiki: https://gitverse.ru/cloud-castle/memcached/wiki
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano