Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 139 · Практика

APCu: кеш данных, сроки жизни, счётчики и обход записей

Полный API APCu: от первого сохранённого массива до атомарных операций, статистики, всех настроек и диагностического обхода.

Задача: не пересобирать один справочник при каждом запросе

Представьте страницу магазина: названия статусов и дерево категорий меняются редко, но нужны каждому посетителю. PHP может каждый раз загружать и преобразовывать их заново. APCu позволяет оставить подготовленные данные рядом с обработчиками PHP и брать их повторно. Если копия исчезнет, страница должна уметь восстановить её из настоящего источника.

Один ключ shop:v1:labels и два пути к результату
  1. Запрос страницы → чтение shop:v1:labels
  2. Запись есть → PHP получает массив подписей
  3. Промах → приложение загружает и преобразует исходные данные
  4. Сохраняет готовый массив на выбранный срок → строит страницу

Кеш похож на рабочую полку с подписанными коробками: вы кладёте туда часто нужные готовые детали. Но полка здесь ограничена памятью и может быть полностью освобождена. Это не база заказов и не договор о сохранности данных. Если массив и вызов функции ещё незнакомы, сначала разберите их начальные примеры.

Самая маленькая запись и чтениеСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:greeting', 'Добро пожаловать', 60);
$text = apcu_fetch('shop:greeting', $found);
if ($found) echo $text, "\n";
Ожидаемый результат
Добро пожаловать

Скобки вызывают функцию; запятые разделяют аргументы. Строка shop:greeting — имя записи, строка приветствия — её данные. Результат чтения присваивается $text, отдельный флаг $found сообщает, нашлась ли запись.

Где работает APCu и как подготовить учебное окружение

APCu — отдельное расширение, оно не входит автоматически в любой PHP. Источник пакета и подходящих Windows DLL — официальная страница APCu. Здесь контракт и примеры сверены с 5.1.28, а не с абстрактной версией «установите последнюю». Подбирают PHP-ветку, x64/x86, TS/NTS и компилятор. Настройку делают в ini именно нужного обработчика: веб, CLI, FPM могут различаться.

Включить совместимый модуль только для учебной командыФрагмент или команда
php -d extension=apcu -d apc.enable_cli=1 example.php

Команда для установленного совместимого APCu в extension_dir. Если DLL/so лежит отдельно, укажите её полный путь. Она не устанавливает пакет и не меняет конфигурацию сервера; для Windows имя может быть php_apcu.dll.

В Windows нужен доступный временный каталог: проверяются TMP, TEMP, USERPROFILE, затем Windows directory. На Unix выбор памяти зависит от сборки mmap/IPC. Отдельные независимые CLI-запуски не становятся одним общим кешем с веб-сервером. Совместное использование памятью обработчиков зависит от процессной модели; отдельные машины в любом случае имеют независимые данные.

Старый APC совмещал кеш пользовательских значений и PHP-кода. APCu оставляет пользовательские данные; OPcache обслуживает подготовленный PHP-код. Старые apc_fetch/apc_store и cache_type не следует автоматически переименовывать без проверки. apcu-bc для совместимости с APC не поддерживает PHP8; новый код использует apcu_*.

От простого чтения к функции с восстановлением данных

Два обращения, один расчётСамостоятельный пример
<?php
declare(strict_types=1);

$builds = 0;
function loadCatalogLabels(int &$builds): array {
    $cached = apcu_fetch('shop:v1:catalog-labels', $found);
    if ($found) return $cached;
    $builds++;
    $labels = ['tools' => 'Инструменты', 'parts' => 'Запчасти'];
    apcu_store('shop:v1:catalog-labels', $labels, 60);
    return $labels;
}
echo loadCatalogLabels($builds)['tools'], "\n";
echo loadCatalogLabels($builds)['parts'], "\n";
echo 'Расчётов: ', $builds, "\n";
Ожидаемый результат
Инструменты
Запчасти
Расчётов: 1

Функция возвращает подготовленный массив независимо от успешности кеш-записи. Счётчик по ссылке нужен только для наблюдения в уроке. В реальном проекте массив мог бы получиться из подтверждённого ответа API или выборки БД, но обработка отказов источника остаётся отдельной обязанностью.

Этот путь называют cache-aside. Он не удерживает глобальную блокировку во время расчёта, поэтому при параллельном промахе два запроса могут сделать одинаковую работу. Для дешёвой операции это допустимо. apcu_entry уменьшает такое повторение ценой общей блокировки во время callback; выбор зависит от стоимости и длительности операции, а не красоты одной строки.

Срок жизни, устаревшие данные и версии ключей

TTL=60 означает срок годности записи в секундах, а не таймер, который обязательно проснётся и удалит байты ровно через минуту. При истечении запись считается непригодной для обычного чтения; физическое освобождение происходит в ходе операций. TTL=0 не отменяет очистку при нехватке памяти и перезапуске. Настройка apc.ttl отдельно действует на неиспользуемые записи без индивидуального срока.

СитуацияПолитика приложения
Категория переименованаПосле успешной записи в базу инвалидировать соответствующий ключ или сменить поколение.
Курс доставки от APIЗадать допустимую устарелость и отдельный сценарий при недоступном API.
Изменился формат массиваИзменить версию ключа: shop:v1 → shop:v2, чтобы старый и новый код не читали несовместимые данные.
Кеш очищен целикомВосстановить данные из источника и учитывать всплеск нагрузки.
Несколько узлов приложенияСогласовать invalidation через общее хранилище/события либо выбрать распределённый кеш.

В ключ включают всё, от чего зависит результат: идентификатор магазина, язык, набор прав, версию алгоритма. Нельзя положить персональную страницу в общий ключ page:orders и затем показать её другому пользователю. Префикс отделяет имена, но не является изоляцией безопасности между недоверенными приложениями одного экземпляра.

Все настройки: память, TTL, сериализация и различия версий

НастройкаПо умолчанию / областьЧто меняет
apc.enabled1 / INI_SYSTEMВключённость пользовательского кеша; наличие загруженной DLL само по себе недостаточно.
apc.shm_size32M / INI_SYSTEMРазмер памяти APCu. M/G — сокращения размера, не число записей. Нужен запас на ключи и внутреннее представление.
apc.entries_hint0 в ini / INI_SYSTEM0 выбирает автоматическую ёмкость таблицы; с 5.1.25 ориентир 512 записей на MiB выделенной памяти. До 5.1.25 стандартный ориентир был 4096. Это подсказка, а не жёсткий максимум.
apc.ttl0 / INI_SYSTEMДля записей без индивидуального TTL: неиспользуемые достаточно долго записи становятся кандидатами на удаление при обслуживании памяти. Не гарантирует точное исчезновение в заданную секунду.
apc.gc_ttl3600 / INI_SYSTEMСрок удержания в списке уборки после удаления, если ещё есть ссылки. 0 отключает очистку по времени; при нуле ссылок очистка возможна. Не срок пригодности бизнес-данных.
apc.enable_cli0 / INI_SYSTEMРазрешить APCu в CLI. Полезно для учебного запуска или долгоживущего воркера. Отдельные короткие команды не получают автоматически общую память веб-процесса.
apc.use_request_time0 / INI_ALL0 — текущее время для TTL; 1 — время начала запроса. До 5.1.19 стандартом было 1. В долгом скрипте это меняет поведение срока жизни.
apc.serializerphp / INI_SYSTEMСериализатор сложных данных. Сторонний вариант должен действительно присутствовать и быть совместимым; до 5.1.15 значение по умолчанию называлось default.
apc.slam_defense0 / INI_SYSTEMМеханизм отклонения частых конкурирующих вставок одного ключа. Не гарантия единственного выполнения пользовательского расчёта и не замена правильной блокировке.
apc.preload_pathпусто / INI_SYSTEMДоверенная директория файлов .data с PHP-сериализованными данными, загружаемыми при старте; имя файла без расширения становится ключом. В 5.1.28 доступно только NTS, в ZTS завершается ошибкой. Это не preload PHP-классов OPcache; никогда не используйте пользовательские загрузки.
apc.coredump_unmap0 / INI_SYSTEMПопытка исключить разделяемую память из core dump в обработчике фатального сигнала. Может приводить к неопределённому поведению; не универсальная настройка стабильности.
apc.mmap_file_maskпусто / INI_SYSTEM, только mmap-сборкиИсторический mktemp-шаблон с шестью X, например /tmp/apc.XXXXXX; пустое значение выбирает anonymous mmap. В 5.1.28 прямого специального shm_open режима по .shm в apc_mmap.c уже нет: не переносите старые рецепты без проверки сборки.
apc.mmap_hugepage_size0 / INI_SYSTEM, только mmap-сборкиДополнительная настройка 5.1.28: 0 — без явного размера hugepage; ненулевой размер требует поддержки/резерва ОС и кратности apc.shm_size. Неверный профиль может помешать старту PHP.
apc.smart0 / INI_SYSTEMСлужебный порог очистки относительно размера вставки: множитель для требуемого запаса свободной памяти. Не документирован как универсальная прикладная настройка; менять без измерений и проверки версии не следует.
apc.shm_segmentsисторическая строка официальной таблицыВ реализации 5.1.28 отсутствует, поддержка нескольких сегментов удалена. Не выдаём её за работающий способ увеличить объём; используйте актуальный shm_size и ограничения ОС.

INI_SYSTEM задают при запуске/configuration сервера; обычный ini_set внутри страницы не делает их динамически изменяемыми. apc.use_request_time имеет INI_ALL, но изменение источника времени внутри одной долгой задачи легко запутает расчёт сроков. По умолчанию современная версия использует текущее время.

Некоторые официальные описания сохранили термин «compiler cache», режим .shm и увеличение числа сегментов от прежнего APC. В этой главе они отмечены как исторические, а текущие ограничения сверены по точной реализации. В 5.1.28 слишком большая отдельная запись уже не должна провоцировать прежнее поведение полного опустошения кеша; это не отменяет необходимости выбирать разумный размер данных.

Панель apc.php из пакета показывает устройство и загрузку кеша; графики доступны при GD. Размещать такую диагностику открыто для посетителей нельзя: она раскрывает внутренние ключи и может предоставлять управление. Для мониторинга обычно достаточно apcu_cache_info с limited=true.

Все константы и соответствие полям результата

КонстантаПоле / рольПрименение
APC_ITER_TYPEtypeТип user; это пользовательские значения, не файлы PHP.
APC_ITER_KEYkeyИмя записи внутри массива current().
APC_ITER_VALUEvalueКопия самого значения; не включайте для отчёта, которому достаточно имён.
APC_ITER_NUM_HITSnum_hitsЧисло попаданий по записи.
APC_ITER_MTIMEmtimeВремя изменения.
APC_ITER_CTIMEcreation_timeВремя создания.
APC_ITER_DTIMEdeletion_timeВремя удаления для удерживаемых удалённых записей.
APC_ITER_ATIMEaccess_timeВремя доступа.
APC_ITER_REFCOUNTref_countВнутренний счётчик удержания записи, не число ваших переменных PHP.
APC_ITER_MEM_SIZEmem_sizeЗанятая записью память с расходами представления.
APC_ITER_TTLttlЗаданный срок жизни; не обратный отсчёт.
APC_ITER_NONEнет полейcurrent() выдаёт пустой массив, но key() остаётся доступен.
APC_ITER_ALLвсе поддерживаемые поляПолная маска, а не гарантия наличия полей старого APC.
APC_LIST_ACTIVEтип спискаАктивный список кеша.
APC_LIST_DELETEDтип спискаУже удалённые записи, ещё ожидающие окончательного освобождения; может оказаться пустым.
APC_ITER_DEVICE / APC_ITER_FILENAME / APC_ITER_INODE / APC_ITER_MD5исторические имена из официальной таблицыВ APCu 5.1.28 не определены. Относились к сведениям о файлах старого APC; не используйте без defined и подходящей версии.
Объединить ровно два поляСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ', 60);
$it = new APCUIterator(['shop:17'], APC_ITER_KEY | APC_ITER_TTL);
foreach ($it as $entry) echo $entry['key'], ': ', $entry['ttl'], "\n";
Ожидаемый результат
shop:17: 60

Оператор | объединяет битовые флаги. Значение value здесь не запрашивается, но имя и TTL доступны. Исторические неопределённые константы PHP8 превращают в Error — это не молчаливый пропуск поля.

Что гарантирует атомарность и чего она не заменяет

ОперацияПолезная гарантияГраница
apcu_addНе заменит уже существующий ключfalse также означает другой отказ; утрата кеша отменяет состояние.
apcu_inc / apcu_decОдно изменение целогоНе объединяет несколько ключей и не гарантирует сохранность счётчика.
apcu_casСравнение и замена одного числаНе сравнивает массив; не замечает цикл значения A→B→A.
apcu_entryПромах и короткий callback под блокировкойБлокируется весь экземпляр кеша, не только этот ключ.

Число товара в корзине, деньги и факт обработки платежа требуют устойчивого источника истины. Локальный кеш можно использовать для ускорения чтения, но нельзя выводить из его атомарного счётчика обещание единственного списания денег. Для последнего важны транзакции и идемпотентность обработки событий.

Как устроен обход: порции, поля, позиция и статистика

APCUIterator получает список интересующих ключей или regex, выбирает нужные поля и извлекает записи порциями. foreach сам вызывает rewind, valid, current, key и next. Не полагайтесь на порядок хеш-таблицы как на сортировку товаров. Увеличение chunk_size уменьшает число порций, но может дольше удерживать блокировку и копировать больше данных за шаг.

Это не транзакционный снимок: пока обход читает следующую порцию, другие запросы могут менять кеш. Первый getTotalCount/getTotalHits/getTotalSize рассчитывает и сохраняет все три сводных числа в объекте; для обновления создают новый итератор. Отдельно учитывайте версионные отличия: в 5.1.28 current/key на пустой позиции выбрасывают Error, next возвращает void, размер порции 0 допустим. Карточки ниже показывают каждый шаг.

Полный справочник APCu по действиям

НужноФункции / методы
Сохранить и прочитатьapcu_store · apcu_add · apcu_fetch · apcu_exists
Посчитать при промахеapcu_entry
Изменить счётчикapcu_inc · apcu_dec · apcu_cas
Удалитьapcu_delete · apcu_clear_cache
Диагностикаapcu_enabled · apcu_cache_info · apcu_key_info · apcu_sma_info
Выборка и обходAPCUIterator · APCUIterator::__construct · APCUIterator::rewind · APCUIterator::valid · APCUIterator::current · APCUIterator::key · APCUIterator::next
Агрегаты выборкиAPCUIterator::getTotalCount · APCUIterator::getTotalHits · APCUIterator::getTotalSize

Когда кеш ускоряет, а когда только добавляет работу

Хороший кандидат — многократно используемый результат, восстановление которого заметно дороже чтения из кеша. Если вы кешируете результат сложения двух чисел, lookup и копирование легко окажутся дороже самого вычисления. Для большого массива учитывайте сериализацию, память, копирование каждого чтения и длительность удержания блокировки.

Измеряйте холодный и прогретый режим отдельно: время ответа, нагрузку на источник, hit/miss, объём памяти, expunges и распределение размеров записей. Слишком много уникальных ключей может вытеснять полезные данные. Нельзя обещать фиксированное ускорение только потому, что используется кеш. Подход к измерению разобран в главе производительности.

APCu локален и быстр за счёт памяти рядом с PHP. Если данные должны быть общими между независимыми процессами/узлами и CLI-задачами, рассматривают отдельное общее хранилище с собственными гарантиями. Выбор такого сервиса не отменяет проверки TTL, ошибок подключения и безопасности ключей.

Практика: кешировать в том числе ответ «скидок нет»

Задача: источник для магазина возвращает false, когда скидки выключены. При двух обращениях расчёт должен произойти один раз. Нельзя использовать if (!$value) для определения промаха. После смены настройки удалите только свой ключ.

Решение с явным признаком попаданияСамостоятельный пример
<?php
declare(strict_types=1);

$calls = 0;
function discountAvailable(int &$calls): bool {
    $value = apcu_fetch('shop:v1:discount-available', $found);
    if ($found) return $value;
    $calls++;
    $value = false;
    apcu_store('shop:v1:discount-available', $value, 30);
    return $value;
}
var_dump(discountAvailable($calls));
var_dump(discountAvailable($calls));
echo $calls, "\n";
apcu_delete('shop:v1:discount-available');
var_dump(discountAvailable($calls));
echo $calls, "\n";
Ожидаемый результат
bool(false)
bool(false)
1
bool(false)
2

Признак $found отделён от данных. Два первых вызова используют один расчёт, после адресного удаления данные восстанавливаются. Дальше попробуйте добавить идентификатор магазина в ключ и объяснить, почему результат разных магазинов нельзя смешивать.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

apcu_storeСохранить рассчитанное значение или заменить его новую версию.

APCu 4.0.0+ · APCu

apcu_store(string|array $key, mixed $value = ..., int $ttl = 0): bool|array

Сохранить рассчитанное значение или заменить его новую версию.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyСтрока для одной записи либо массив имя => значение для пакетной записи. Имена должны включать приложение, версию формата и нужные измерения: язык, магазин, права.
valueДля строкового key — сохраняемое PHP-значение. Для массива ключей аргумент не используется; указывают null, если нужен третий позиционный ttl.
ttlСрок жизни в секундах; 0 — без заданного срока, но без гарантии сохранности до вечности. Выбирайте неотрицательное целое в разумных границах.
returnОдна запись: bool успеха. Массив: ключи неудавшихся записей с кодом -1; пустой массив означает отсутствие ошибок. Это не общая транзакция.

Данные копируются в кеш. Изменение исходного массива не меняет сохранённую запись. Не сохраняйте PDO-соединения, открытые файловые ресурсы или замыкания как переносимое состояние: кешируйте обычные данные, необходимые для повторного результата. Объекты могут требовать сериализации и доступного определения класса; чтение — не общий живой объект для всех запросов.

Сохранить название категорииСамостоятельный пример
<?php
declare(strict_types=1);

$saved = apcu_store('shop:v1:category:7', 'Инструменты', 60);
if (!$saved) throw new RuntimeException('Кеш не принял запись');
echo apcu_fetch('shop:v1:category:7'), "\n";
Ожидаемый результат
Инструменты

Первый аргумент — адрес ячейки, второй — содержимое, 60 — секунды. Кеш не отправляет данные посетителю: вывод выполняет echo.

Изменить цену и явно записать новую версиюСамостоятельный пример
<?php
declare(strict_types=1);

$product = ['name' => 'Ключ', 'price' => 800];
apcu_store('shop:v1:product:17', $product, 60);
$product['price'] = 900;
echo apcu_fetch('shop:v1:product:17')['price'], "\n";
apcu_store('shop:v1:product:17', $product, 60);
echo apcu_fetch('shop:v1:product:17')['price'], "\n";
Ожидаемый результат
800
900

Исходный массив и кеш — разные состояния. Замена по тому же ключу разрешена store; add её запрещает.

Положить две настройки с общим TTLСамостоятельный пример
<?php
declare(strict_types=1);

$failed = apcu_store(['shop:currency' => 'RUB', 'shop:language' => 'ru'], null, 60);
echo count($failed), "\n";
echo apcu_fetch('shop:currency'), "\n";
Ожидаемый результат
0
RUB

Проверяйте массив ошибок, а не if ($failed) как флаг успеха. При ошибке кеша рабочее приложение обычно продолжает с уже рассчитанными данными.

Следующий инструмент: apcu_add; apcu_fetch; apcu_delete.

apcu_addДобавить значение только при отсутствии ключа.

APCu 4.0.0+ · APCu

apcu_add(string|array $key, mixed $value = ..., int $ttl = 0): bool|array

Добавить значение только при отсутствии ключа.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
key / valueОдна пара либо массив пар; пакетная форма устроена как у store.
ttlСекунды для добавленной записи; не продлевает жизнь уже существующей.
returntrue при успешном добавлении одной пары; false при занятом ключе или ином отказе. Для массива возвращаются только неудавшиеся ключи с -1.

Это атомарное «создать, если нет», полезное для начального состояния. Последовательность exists, затем store не даёт того же обещания: между двумя вызовами другой процесс может записать значение. Однако false не различает занятой ключ и нехватку памяти.

Не затереть уже выбранную валютуСамостоятельный пример
<?php
declare(strict_types=1);

var_dump(apcu_add('shop:currency', 'RUB', 60));
var_dump(apcu_add('shop:currency', 'EUR', 60));
echo apcu_fetch('shop:currency'), "\n";
Ожидаемый результат
bool(true)
bool(false)
RUB

Второй автор предложения не перезаписывает первое. Это не постоянное хранение пользовательского выбора — для него нужна база или сессия.

Увидеть, какой из начальных ключей уже занятСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:language', 'ru');
$failed = apcu_add(['shop:language' => 'en', 'shop:currency' => 'RUB'], null, 60);
echo implode(', ', array_keys($failed)), "\n";
echo apcu_fetch('shop:currency'), "\n";
Ожидаемый результат
shop:language
RUB

Часть набора может добавиться, часть — нет. Поэтому batch нельзя выдавать за транзакционную блокировку нескольких данных.

Короткий add с TTL иногда используют для подавления повторной работы. Но истёкшая запись, перезапуск и отсутствие проверки владельца при delete делают примитивную схему ненадёжным распределённым замком. Подтверждение платежа и единственность заказа закрепляют транзакцией/уникальным ограничением в постоянном хранилище.

Следующий инструмент: apcu_store; apcu_exists; apcu_cas.

apcu_fetchПолучить сохранённое значение и отличить false от промаха.

APCu 4.0.0+ · APCu

apcu_fetch(string|array $key, bool &$success = null): mixed

Получить сохранённое значение и отличить false от промаха.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyОдна строка либо список строк. В batch отсутствующие ключи не попадают в результат.
successВыходная переменная по ссылке: для одного ключа сообщает попадание. В batch означает обработку массива, а не наличие всех ключей.
returnОдна запись — само значение любого поддерживаемого типа, при промахе false. Список — массив найденных key => value.

Кеш может совершенно законно хранить false, 0, пустую строку, пустой массив и null. if (!$value) смешивает эти значения с промахом. Передайте второй аргумент, и после вызова PHP запишет в него отдельный признак.

Прочитать отрицательный результат проверкиСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:feature:delivery', false, 60);
$value = apcu_fetch('shop:feature:delivery', $found);
var_dump($found, $value);
$missing = apcu_fetch('shop:feature:unknown', $found);
var_dump($found, $missing);
Ожидаемый результат
bool(true)
bool(false)
bool(false)
bool(false)

Первое false — сохранённый ответ «доставка недоступна», второе — отсутствие записи. $found позволяет выбрать правильную ветку.

Не потерять отсутствующие товары в пакетном чтенииСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', ['name' => 'Ключ']);
$keys = ['shop:17', 'shop:18'];
$found = apcu_fetch($keys, $batchProcessed);
foreach ($keys as $key) {
    echo $key, ': ', array_key_exists($key, $found) ? 'есть' : 'нужно загрузить', "\n";
}
Ожидаемый результат
shop:17: есть
shop:18: нужно загрузить

Проверка array_key_exists сохраняет смысл даже если кеш содержит null. После batch загружают только отсутствующие значения.

Обычный cache-aside состоит из fetch → при промахе расчёт → store. Несколько запросов могут одновременно пересчитать одно значение; такая схема допустима для дешёвого расчёта и не равна атомарному apcu_entry. Проверка существования перед fetch только увеличивает число вызовов и не удерживает запись от удаления.

Следующий инструмент: apcu_store; apcu_entry; apcu_exists.

apcu_existsПроверить присутствие ключа, не получать его значение.

APCu 4.0.0+ · APCu

apcu_exists(string|array $keys): bool|array

Проверить присутствие ключа, не получать его значение.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keysСтрока либо список строк; значения не возвращаются.
returnДля строки bool; для списка массив существующих ключей со значением true, либо пустой массив.
Наличие записи не равно истинности её содержимогоСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:discount-enabled', false);
var_dump(apcu_exists('shop:discount-enabled'));
var_dump(apcu_exists('shop:unknown'));
Ожидаемый результат
bool(true)
bool(false)

Функция отвечает только о ячейке. Значение false не делает запись отсутствующей.

Проверить подготовленность двух справочниковСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:categories', ['Крепёж']);
$present = apcu_exists(['shop:categories', 'shop:brands']);
echo implode(', ', array_keys($present)), "\n";
Ожидаемый результат
shop:categories

При построении диагностического отчёта содержимое справочника не нужно. Если хотите сразу использовать данные, выбирайте fetch с $success.

Успешная проверка — наблюдение в конкретный момент. Между exists и следующим действием запись может исчезнуть. Не строите на ней гарантию «заказ ещё не обрабатывается».

Следующий инструмент: apcu_fetch; apcu_add; apcu_key_info.

apcu_deleteУбрать устаревшую копию по ключам или выборке.

APCu 4.0.0+ · APCu

apcu_delete(string|array|APCUIterator $key): bool|array

Убрать устаревшую копию по ключам или выборке.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyОдна строка, список строк либо APCUIterator с фильтром.
returnДля строки — успех удаления. Для массива — список ключей, которые удалить не удалось, в том числе отсутствующих. Для итератора — bool обработки, не отчёт о каждом ключе.
После смены товара удалить его старое представлениеСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:v1:product:17', ['price' => 800]);
var_dump(apcu_delete('shop:v1:product:17'));
var_dump(apcu_exists('shop:v1:product:17'));
var_dump(apcu_delete('shop:v1:product:17'));
Ожидаемый результат
bool(true)
bool(false)
bool(false)

Сначала в реальном приложении успешно фиксируют изменение в основной базе, затем инвалидируют кеш. Здесь база намеренно не имитируется несуществующим вызовом.

Отличить удалённые записи от уже отсутствующихСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$failed = apcu_delete(['shop:17', 'shop:18']);
echo implode(', ', $failed), "\n";
Ожидаемый результат
shop:18

Возвращаются ошибки, а не список удачных удалений. Повторное удаление уже отсутствующей кеш-копии в сценарии инвалидирования часто не требует аварии.

Удалить только кеш своего разделаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:v1:17' => 'Ключ', 'shop:v1:18' => 'Пила', 'other:17' => 'Не трогаем']);
apcu_delete(new APCUIterator('~^shop:v1:~', APC_ITER_KEY));
var_dump(apcu_exists('shop:v1:17'), apcu_exists('other:17'));
Ожидаемый результат
bool(false)
bool(true)

Шаблон явно ограничен нашим префиксом. Перебор не является транзакционным снимком: конкурентные новые записи требуют продуманного версионирования ключей.

Следующий инструмент: apcu_clear_cache; APCUIterator::__construct; apcu_store.

apcu_entryВернуть готовые данные либо атомарно вычислить отсутствующие.

APCu 5.1.0+ · APCu

apcu_entry(string $key, callable $callback, int $ttl = 0): mixed

Вернуть готовые данные либо атомарно вычислить отсутствующие.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyИмя записи.
callbackВызываемый обработчик получает один аргумент — ключ. Его return становится значением; при попадании обработчик вообще не запускается.
ttlСрок новой записи в секундах. Попадание не пересоздаёт её с новым сроком.
returnГотовое либо вычисленное значение. Исключение callback распространяется; это не автоматическое кэширование успешного ответа сервиса.

В этой функции эксклюзивная блокировка относится к кешу, а не только одному ключу. Пока callback занят, другие операции APCu тоже ждут. Внутри обработчика безопасно вызывать из API APCu только apcu_entry, как прямо оговаривает контракт. Медленный HTTP-запрос под такой блокировкой способен затормозить весь экземпляр кеша.

Построить таблицу подписей только при первом обращенииСамостоятельный пример
<?php
declare(strict_types=1);

$calls = 0;
$build = function (string $key) use (&$calls): array {
    $calls++;
    return ['paid' => 'Оплачен', 'new' => 'Новый'];
};
$first = apcu_entry('shop:status-labels', $build, 60);
$second = apcu_entry('shop:status-labels', $build, 60);
echo $second['paid'], "\n", $calls, "\n";
Ожидаемый результат
Оплачен
1

Имя обработчика передают без скобок вызова. APCu сам вызывает его только на промахе; use (&$calls) здесь нужен лишь для видимого счётчика запусков.

Не превратить сбой расчёта в успешное значениеСамостоятельный пример
<?php
declare(strict_types=1);

try {
    apcu_entry('shop:broken', function (string $key): array {
        throw new RuntimeException('Источник временно недоступен');
    }, 60);
} catch (RuntimeException $error) {
    echo $error->getMessage(), "\n";
}
echo apcu_entry('shop:broken', fn(string $key) => 'Восстановлено', 60), "\n";
Ожидаемый результат
Источник временно недоступен
Восстановлено

Не перехватываем ошибку внутри callback с return пустого каталога: такой пустой каталог стал бы закешированным нормальным результатом. Повтор возможен после устранения причины.

Если вычисление вернуло false или null, это допустимые данные и они кешируются. Возвращённое вычисленное значение само по себе не является подтверждением вечного хранения: приложение всё равно должно переживать следующий промах. Для тяжёлой внешней зависимости рассматривают предварительный прогрев, очередь и stale-while-revalidate с отдельной политикой свежести.

Следующий инструмент: apcu_fetch; apcu_store; apcu_add.

apcu_incАтомарно увеличить целочисленный счётчик.

APCu 4.0.0+ · APCu

apcu_inc(string $key, int $step = 1, bool &$success = null, int $ttl = 0): int|false

Атомарно увеличить целочисленный счётчик.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyИмя целочисленной записи. Отсутствующая запись создаётся от нуля с применением шага.
stepВеличина изменения, по умолчанию 1. Отрицательный шаг меняет направление; задавайте явную политику допустимых чисел.
successВыходной bool по ссылке; позволяет отличить успешный ноль от отказа.
ttlСекунды только для создаваемой записи. Обновление существующей не переносит начало её жизни.
returnНовое int либо false, например если под ключом строка/массив вместо целого.

Чтение числа, арифметика в PHP и store — три отдельных действия. Два параллельных запроса могут прочитать одинаковое старое число и потерять одно изменение. Эта функция объединяет изменение одного целого; несколько независимых ключей общей транзакцией от этого не становятся.

Изменить новый счётчик дваждыСамостоятельный пример
<?php
declare(strict_types=1);

echo apcu_inc('shop:events', 2, $ok, 60), "\n";
echo apcu_inc('shop:events', 3, $ok, 60), "\n";
Ожидаемый результат
2
5

На отсутствующем ключе исходной величиной служит ноль. Повторный вызов продолжает существующий счётчик, а не начинает его заново.

Увидеть ошибку схемы и корректно прочитать нольСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:wrong', '10');
var_dump(apcu_inc('shop:wrong', 1, $ok), $ok);
apcu_store('shop:zero', 0);
var_dump(apcu_inc('shop:zero', 0, $ok), $ok);
Ожидаемый результат
bool(false)
bool(false)
int(0)
bool(true)

Строка с цифрами не стала счётчиком int автоматически. Ошибку не исправляют бездумным приведением чужой кеш-записи: сначала проверяют происхождение ключа.

Подходит для приблизительной статистики или локального ограничения нагрузки с выбранной политикой сброса. Для денег, складского остатка и обязательного общего rate limit по нескольким серверам APCu недостаточен: память может исчезнуть, узлы изолированы. Переполнение машинного int нельзя использовать как бизнес-правило; ограничивайте диапазон и период сброса.

Следующий инструмент: apcu_dec; apcu_cas; apcu_add.

apcu_decАтомарно уменьшить целочисленный счётчик.

APCu 4.0.0+ · APCu

apcu_dec(string $key, int $step = 1, bool &$success = null, int $ttl = 0): int|false

Атомарно уменьшить целочисленный счётчик.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyИмя целочисленной записи. Отсутствующая запись создаётся от нуля с применением шага.
stepВеличина изменения, по умолчанию 1. Отрицательный шаг меняет направление; задавайте явную политику допустимых чисел.
successВыходной bool по ссылке; позволяет отличить успешный ноль от отказа.
ttlСекунды только для создаваемой записи. Обновление существующей не переносит начало её жизни.
returnНовое int либо false, например если под ключом строка/массив вместо целого.

Чтение числа, арифметика в PHP и store — три отдельных действия. Два параллельных запроса могут прочитать одинаковое старое число и потерять одно изменение. Эта функция объединяет изменение одного целого; несколько независимых ключей общей транзакцией от этого не становятся.

Изменить новый счётчик дваждыСамостоятельный пример
<?php
declare(strict_types=1);

echo apcu_dec('shop:events', 2, $ok, 60), "\n";
echo apcu_dec('shop:events', 3, $ok, 60), "\n";
Ожидаемый результат
-2
-5

На отсутствующем ключе исходной величиной служит ноль. Повторный вызов продолжает существующий счётчик, а не начинает его заново.

Увидеть ошибку схемы и корректно прочитать нольСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:wrong', '10');
var_dump(apcu_dec('shop:wrong', 1, $ok), $ok);
apcu_store('shop:zero', 0);
var_dump(apcu_dec('shop:zero', 0, $ok), $ok);
Ожидаемый результат
bool(false)
bool(false)
int(0)
bool(true)

Строка с цифрами не стала счётчиком int автоматически. Ошибку не исправляют бездумным приведением чужой кеш-записи: сначала проверяют происхождение ключа.

Подходит для приблизительной статистики или локального ограничения нагрузки с выбранной политикой сброса. Для денег, складского остатка и обязательного общего rate limit по нескольким серверам APCu недостаточен: память может исчезнуть, узлы изолированы. Переполнение машинного int нельзя использовать как бизнес-правило; ограничивайте диапазон и период сброса.

Следующий инструмент: apcu_inc; apcu_cas; apcu_add.

apcu_casЗаменить целое только если его прежнее значение ещё совпадает.

APCu 4.0.0+ · APCu

apcu_cas(string $key, int $old, int $new): bool

Заменить целое только если его прежнее значение ещё совпадает.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyУже существующая целочисленная запись.
oldОжидаемое прежнее число; сравнивается атомарно внутри операции.
newНовое число, которое будет записано при совпадении.
returntrue при замене; false при несовпадении, отсутствии или непригодном типе. Нет автоматического создания отсутствующего ключа.
Не затереть уже сменившееся поколение каталогаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:generation', 7);
var_dump(apcu_cas('shop:generation', 7, 8));
var_dump(apcu_cas('shop:generation', 7, 9));
echo apcu_fetch('shop:generation'), "\n";
Ожидаемый результат
bool(true)
bool(false)
8

Второй запрос всё ещё думал, что версия равна 7. CAS обнаружил устаревшее ожидание и не затёр 8 значением 9.

Отсутствие и неверный тип не равны начальному состояниюСамостоятельный пример
<?php
declare(strict_types=1);

var_dump(apcu_cas('shop:missing', 0, 1));
apcu_store('shop:text', '0');
var_dump(apcu_cas('shop:text', 0, 1));
apcu_add('shop:state', 0, 60);
var_dump(apcu_cas('shop:state', 0, 1));
Ожидаемый результат
bool(false)
bool(false)
bool(true)

Создание и условная замена — разные действия. add создаёт отсутствующее начальное значение, CAS работает с ожидаемым существующим.

Операция не сравнивает массивы и не обещает «с тех пор ничего не менялось»: последовательность 7→8→7 вновь удовлетворит old=7 (проблема ABA). Не используйте её вместо подтверждённого уникального идентификатора операции и транзакции постоянного хранилища. В цикле повторов задают предел попыток, иначе высокая конкуренция создаёт бесконечную работу.

Следующий инструмент: apcu_add; apcu_inc; apcu_dec.

apcu_enabledПроверить, можно ли использовать APCu именно в этом окружении.

APCu 4.0.3+ · APCu

apcu_enabled(): bool

Проверить, можно ли использовать APCu именно в этом окружении.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returntrue — APCu пригоден здесь; false — расширение загружено, но пользовательский кеш выключен. Если расширения вообще нет, самого имени функции тоже нет.
Выбрать кеш или прямое вычисление без fatal errorСамостоятельный пример
<?php
declare(strict_types=1);

$usable = function_exists('apcu_enabled') && apcu_enabled();
echo $usable ? "Кеш доступен\n" : "Считаем напрямую\n";
Ожидаемый результат
Кеш доступен

Сначала function_exists, затем &&: правая часть не выполняется при отсутствующей функции. На хостинге без APCu этот же код выберет вторую строку.

Сохранить работоспособность загрузки каталога без кешаСамостоятельный пример
<?php
declare(strict_types=1);

function categoryLabels(): array {
    if (!function_exists('apcu_enabled') || !apcu_enabled()) {
        return ['tools' => 'Инструменты'];
    }
    return apcu_entry('shop:labels', fn(string $key) => ['tools' => 'Инструменты'], 60);
}
echo categoryLabels()['tools'], "\n";
Ожидаемый результат
Инструменты

Ускорение не заменяет полезную работу. Для учебной демонстрации источник — фиксированный маленький массив; загрузку большого внешнего источника не стоит держать под глобальной блокировкой entry.

Проверяйте SAPI, версию расширения и соответствующий ini. Веб-страница phpinfo и команда в терминале могут использовать разные конфигурации. Само extension_loaded подтверждает загрузку модуля, но не включённость кеша.

Следующий инструмент: apcu_fetch; apcu_entry.

apcu_clear_cacheОчистить все пользовательские записи текущего экземпляра APCu.

APCu 4.0.0+ · APCu

apcu_clear_cache(): bool

Очистить все пользовательские записи текущего экземпляра APCu.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет; старого cache_type из APC здесь нет.
returnПо документированному контракту всегда true. Это не подтверждение сброса на других серверах, доставки нового HTML или очистки OPcache.
Очистить исключительно свой учебный CLI-кешСамостоятельный пример
<?php
declare(strict_types=1);

// Выполнять только в отдельном учебном процессе.
apcu_store(['lab:a' => 1, 'lab:b' => 2]);
var_dump(apcu_clear_cache());
var_dump(apcu_exists('lab:a'), apcu_exists('lab:b'));
Ожидаемый результат
bool(true)
bool(false)
bool(false)

Команда убирает всё в данном кеше, а не только lab:. На сервере с несколькими приложениями это широкое действие; для одной сущности есть delete.

Показать, почему новый префикс не требует массового сбросаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:v1:labels', ['name' => 'Старая схема'], 60);
apcu_store('shop:v2:labels', ['title' => 'Новая схема'], 60);
$labels = apcu_fetch('shop:v2:labels', $found);
echo $labels['title'], "\n";
echo apcu_exists('shop:v1:labels') ? "Старая запись пока существует\n" : "Нет старой записи\n";
Ожидаемый результат
Новая схема
Старая запись пока существует

Это альтернатива общему сбросу при смене формата: новое приложение использует новые ключи, прежние удаляются согласно TTL и политике релиза. Пока они существуют, расход памяти остаётся.

Очистка создаёт холодный кеш и всплеск пересчётов. Не делайте публичную страницу «?clear=1» без контроля доступа. Запуск из независимого CLI-процесса не очищает общий веб-кеш другого процесса; OPcache и кеш данных очищаются разными механизмами.

Следующий инструмент: apcu_delete; APCUIterator::__construct; apcu_cache_info.

apcu_cache_infoПосмотреть попадания, промахи, число записей и метаданные кеша.

APCu 4.0.0+ · APCu

apcu_cache_info(bool $limited = false): array|false

Посмотреть попадания, промахи, число записей и метаданные кеша.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
limitedfalse включает индивидуальные cache_list/deleted_list и распределение слотов; true оставляет сводку, снижая объём получения.
returnМассив статистики либо false при невозможности получения; выключенный кеш также вызывает E_WARNING.
Поляnum_hits/num_misses, num_entries/num_inserts, expunges, start_time, mem_size, num_slots, ttl, memory_type; точный набор зависит от версии.
Получить сводку без вывода содержимого всех записейСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
apcu_fetch('shop:17');
apcu_fetch('shop:18');
$info = apcu_cache_info(true);
if ($info === false) throw new RuntimeException('Статистика недоступна');
var_dump($info['num_hits'] >= 1, $info['num_misses'] >= 1);
var_dump(array_key_exists('cache_list', $info));
Ожидаемый результат
bool(true)
bool(true)
bool(false)

Счётчики могут расти из других запросов. Здесь проверяем смысл полей, не обещаем фиксированное число попаданий на живом сервере.

Получить только ключи своей лабораторной областиСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('lab:catalog', ['Ключ']);
$info = apcu_cache_info(false);
$keys = [];
foreach ($info['cache_list'] as $entry) {
    if (str_starts_with($entry['info'], 'lab:')) $keys[] = $entry['info'];
}
sort($keys);
echo implode(', ', $keys), "\n";
Ожидаемый результат
lab:catalog

В APCu 5.1.28 имя записи в cache_list называется info; старые примеры APC с filename/device/типом file не описывают пользовательский кеш этой версии.

Рост expunges — повод исследовать память, размеры и кардинальность ключей, а не автоматически удваивать лимит. Полный обход может быть дорогим; сводка limited=true лучше для частого мониторинга. Процент попаданий считают hits/(hits+misses), отдельно обрабатывая нулевой знаменатель. Он не заменяет измерение времени ответа.

Следующий инструмент: apcu_sma_info; apcu_key_info; APCUIterator::getTotalHits.

apcu_key_infoИсследовать метаданные одной записи без извлечения значения.

APCu 4.0.2+ · APCu

apcu_key_info(string $key): ?array

Исследовать метаданные одной записи без извлечения значения.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
keyИмя нужной записи.
returnМассив hits, access_time, mtime, creation_time, deletion_time, ttl, refs либо null при отсутствии. ttl — заданный срок, не готовое количество оставшихся секунд.
Проверить заданный срок жизни справочникаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:labels', ['new' => 'Новый'], 60);
$info = apcu_key_info('shop:labels');
echo $info['ttl'], "\n";
var_dump(apcu_key_info('shop:missing'));
Ожидаемый результат
60
NULL

null означает отсутствие метаданных. В обычной обработке запроса достаточно fetch: диагностические вызовы не нужны для каждого чтения.

Связать чтения с метаданными конкретной записиСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:labels', ['new' => 'Новый']);
$before = apcu_key_info('shop:labels');
apcu_fetch('shop:labels');
$after = apcu_key_info('shop:labels');
echo $after['hits'] - $before['hits'], "\n";
Ожидаемый результат
1

В изолированном процессе выполнено одно чтение. При нескольких обработчиках разность может включать их обращения. Метод не резервирует запись от удаления.

В 5.1.28 этот диагностический поиск не проверяет истечение TTL: метаданные ещё не убранной просроченной записи могут сохраняться. Не заменяйте им fetch/exists для решения, пригодны ли кеш-данные.

Следующий инструмент: apcu_fetch; apcu_cache_info.

apcu_sma_infoПосмотреть доступную общую память и её свободные блоки.

APCu 4.0.0+ · APCu

apcu_sma_info(bool $limited = false): array|false

Посмотреть доступную общую память и её свободные блоки.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
limitedtrue — num_seg, seg_size, avail_mem без подробных списков блоков. false — также block_lists.
returnМассив, при недоступной памяти false с E_WARNING. Размеры в байтах; значения некоторых полей возвращаются float.
ГраницаЭто аллокатор APCu, а не memory_get_usage текущего PHP-скрипта и не общая RAM компьютера.
Проверить, что память действительно выделенаСамостоятельный пример
<?php
declare(strict_types=1);

$info = apcu_sma_info(true);
if ($info === false) throw new RuntimeException('Память кеша недоступна');
var_dump($info['num_seg'] === 1);
var_dump($info['avail_mem'] > 0, $info['avail_mem'] < $info['seg_size']);
Ожидаемый результат
bool(true)
bool(true)
bool(true)

Часть памяти занята служебными структурами ещё до первой пользовательской записи. Размер сегмента не равен полезному объёму значений.

Найти самый большой свободный блокСамостоятельный пример
<?php
declare(strict_types=1);

$info = apcu_sma_info(false);
$largest = 0;
foreach ($info['block_lists'] as $blocks) {
    foreach ($blocks as $block) $largest = max($largest, $block['size']);
}
var_dump($largest > 0);
var_dump($largest <= $info['avail_mem']);
Ожидаемый результат
bool(true)
bool(true)

Суммарно свободных байт может быть много, но распределение на блоки важно для новой большой записи. Современный APCu умеет уплотнять память; конкретный эффект зависит от версии и нагрузки.

В APCu 5.1.28 num_seg равен 1; внешний массив block_lists сохранён для совместимости. Старую инструкцию «добавьте apc.shm_segments» нельзя автоматически переносить на эту реализацию.

Следующий инструмент: apcu_cache_info; APCUIterator::getTotalSize.

APCUIteratorОбходить выбранные записи кеша небольшими порциями.

APCu 5.0.0+ · APCu

class APCUIterator implements Iterator

Обходить выбранные записи кеша небольшими порциями.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
НазначениеВыборка по списку ключей или регулярному выражению; foreach вызывает методы протокола Iterator.
СостояниеСохраняет позицию, порцию найденных записей и рассчитанные totals. Это не массив всех данных и не неизменяемый снимок всего кеша.
ОграниченияТребует включённый APCu. В 5.1.28 объект не клонируется и не предназначен для сериализации как состояние приложения.
Выбрать только товары своего приложенияСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$products = [];
foreach (new APCUIterator('~^shop:~', APC_ITER_KEY | APC_ITER_VALUE) as $entry) {
    $products[$entry['key']] = $entry['value'];
}
ksort($products);
foreach ($products as $key => $value) echo "$key: $value\n";
Ожидаемый результат
shop:17: Ключ
shop:18: Пила

Итератор читает внутренний порядок хеш-таблицы; сортировку для отчёта мы выполняем отдельно. Регулярное выражение ^shop: означает начало ключа, не поиск текста в значениях.

Инвентаризация без извлечения крупных значенийСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$names = [];
foreach (new APCUIterator(['shop:17', 'shop:18'], APC_ITER_KEY) as $entry) {
    $names[] = $entry['key'];
    if (array_key_exists('value', $entry)) throw new RuntimeException('Лишнее поле');
}
sort($names);
echo implode(', ', $names), "\n";
Ожидаемый результат
shop:17, shop:18

Не запрашиваем APC_ITER_VALUE, если нужен только список имён. Это уменьшает копирование и работу сериализатора; сама проверка ключей всё равно имеет стоимость.

Следующий инструмент: APCUIterator::__construct; APCUIterator::valid; apcu_delete.

APCUIterator::__constructНастроить фильтр, поля результата и размер порции обхода.

APCu 5.0.0+ · APCu

new APCUIterator(array|string|null $search = null, int $format = APC_ITER_ALL, int $chunk_size = 0, int $list = APC_LIST_ACTIVE)

Настроить фильтр, поля результата и размер порции обхода.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
searchnull — все; строка — PCRE с разделителями; массив — точные ключи. Не подставляйте пользовательский текст в regex без preg_quote.
formatБитовая маска APC_ITER_*: объединяют через |. NONE даёт пустые данные current(), ALL — все поддерживаемые поля.
chunk_sizeВ 5.1.28 0 выбирает стандартные 100; положительное число задаёт порцию. Это не лимит общего результата и не SQL LIMIT.
listAPC_LIST_ACTIVE либо APC_LIST_DELETED: активные записи или ещё удерживаемые записи очереди удаления. Deleted — не архив истории.
ОшибкаВыключенный APCu — Error. Неправильные format/chunk/list/regex недопустимы; не рассчитывайте на пустую выборку вместо диагностики.
Найти один известный товарСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$iterator = new APCUIterator(['shop:18'], APC_ITER_KEY | APC_ITER_VALUE, 1);
foreach ($iterator as $entry) echo $entry['value'], "\n";
Ожидаемый результат
Пила

Порция 1 относится к работе обхода. Список search содержит точный ключ и не требует знания регулярных выражений.

Маленькая порция не ограничивает общее число записейСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$count = 0;
foreach (new APCUIterator('~^shop:~', APC_ITER_KEY, 1) as $entry) $count++;
echo $count, "\n";
Ожидаемый результат
2

Получены обе записи, хотя chunk_size равен 1. Такой обход уменьшает длину отдельных удержаний блокировки, но не делает полный большой отчёт бесплатным.

В официальной странице встречается значение по умолчанию 100 и требование >0; точный stub/реализация 5.1.28 допускают 0 как выбор стандартной порции. Для переносимого явного вызова можно указать 100. Нужный набор констант и устаревшие имена перечислены в таблице полей.

Следующий инструмент: APCUIterator::current; APCUIterator::key; APCUIterator::getTotalCount.

APCUIterator::currentПолучить данные той записи, на которой находится обход.

APCu 5.0.0+ · APCu

APCUIterator::current(): mixed

Получить данные той записи, на которой находится обход.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returnМассив полей согласно format; при APC_ITER_NONE пустой массив. На недействительной позиции 5.1.28 выбрасывает Error, хотя старое описание обещает false.
Прочитать value из текущего элементаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$it = new APCUIterator(['shop:17'], APC_ITER_VALUE);
$it->rewind();
if ($it->valid()) echo $it->current()['value'], "\n";
Ожидаемый результат
Ключ

Сначала убеждаемся, что позиция существует. current не перемещает курсор, поэтому повтор вернёт тот же выбранный элемент до next.

Показать ошибку чтения из пустой выборкиСамостоятельный пример
<?php
declare(strict_types=1);

$it = new APCUIterator(['shop:missing']);
try { $it->current(); }
catch (Error $error) { echo "Нет текущей записи\n"; }
Ожидаемый результат
Нет текущей записи

В рабочем обходе эту ситуацию предупреждает valid. catch здесь демонстрирует реальное отличие актуального расширения от устаревшего текста справочника.

Следующий инструмент: APCUIterator::valid; APCUIterator::next.

APCUIterator::keyПолучить ключ текущей записи независимо от набора полей.

APCu 5.0.0+ · APCu

APCUIterator::key(): string|int

Получить ключ текущей записи независимо от набора полей.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returnТекущий ключ; для пользовательских APCu-записей обычно строка имени. Полный stub допускает string|int. На недействительной позиции — Error в 5.1.28.
Увидеть имя даже без APC_ITER_KEY в данныхСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$it = new APCUIterator(['shop:17'], APC_ITER_VALUE);
$it->rewind();
if ($it->valid()) echo $it->key(), "\n";
Ожидаемый результат
shop:17

key() — метод протокола обхода, а поле current()[key] зависит от маски format. Не путайте их.

Собрать имена с пустым набором полейСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$keys = [];
foreach (new APCUIterator('~^shop:~', APC_ITER_NONE) as $key => $entry) {
    if ($entry !== []) throw new RuntimeException('Ожидали пустые поля');
    $keys[] = $key;
}
sort($keys);
echo implode(', ', $keys), "\n";
Ожидаемый результат
shop:17, shop:18

foreach использует key() для левой части key => entry. Имя доступно без копирования значения записи.

Следующий инструмент: APCUIterator::current; APCUIterator::valid.

APCUIterator::nextПерейти от текущей позиции к следующей.

APCu 5.0.0+ · APCu

APCUIterator::next(): void

Перейти от текущей позиции к следующей.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returnВ APCu 5.1.28 void; результат вызова не bool успеха. Окончание проверяют valid(). В старой документации указан bool, что не совпадает с текущим stub.
Дойти до конца выборки из одного товараСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$it = new APCUIterator(['shop:17']);
$it->rewind();
var_dump($it->valid());
$it->next();
var_dump($it->valid());
Ожидаемый результат
bool(true)
bool(false)

Вызов next двигает состояние, а не выводит товар и не возвращает его.

Развернуть то, что foreach делает за васСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY);
$keys = [];
for ($it->rewind(); $it->valid(); $it->next()) $keys[] = $it->key();
sort($keys);
echo implode(', ', $keys), "\n";
Ожидаемый результат
shop:17, shop:18

В обычном коде foreach понятнее. Ручная запись нужна для понимания протокола или специального поэтапного обработчика.

Следующий инструмент: APCUIterator::rewind; APCUIterator::valid; APCUIterator::current.

APCUIterator::rewindВернуть обход к началу выборки.

APCu 5.0.0+ · APCu

APCUIterator::rewind(): void

Вернуть обход к началу выборки.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returnНичего не возвращает. Сбрасывает позицию и заново подготавливает порцию; не очищает кеш и не обнуляет кешированные totals объекта.
Повторно прочитать единственную записьСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$it = new APCUIterator(['shop:17'], APC_ITER_KEY);
$it->rewind(); echo $it->key(), "\n";
$it->next();
$it->rewind(); echo $it->key(), "\n";
Ожидаемый результат
shop:17
shop:17

Объект обхода тот же, позиция восстановлена. Это не повторная вставка в кеш.

Выполнить два независимых подсчёта обходомСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY);
foreach ([1, 2] as $pass) {
    $count = 0;
    for ($it->rewind(); $it->valid(); $it->next()) $count++;
    echo "$pass: $count\n";
}
Ожидаемый результат
1: 2
2: 2

В изолированном примере кеш не меняется. На живом сервере между проходами результаты могут отличаться — rewind не фиксирует снимок.

Следующий инструмент: APCUIterator::next; APCUIterator::getTotalCount.

APCUIterator::validПроверить, есть ли элемент на текущей позиции.

APCu 5.0.0+ · APCu

APCUIterator::valid(): bool

Проверить, есть ли элемент на текущей позиции.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет.
returntrue при доступном элементе, false после конца/пустой выборки. Может подгрузить следующую порцию, когда прежняя исчерпана.
Не читать несуществующий результатСамостоятельный пример
<?php
declare(strict_types=1);

$it = new APCUIterator(['shop:missing']);
$it->rewind();
echo $it->valid() ? "Есть запись\n" : "Выборка пуста\n";
Ожидаемый результат
Выборка пуста

Пустая выборка — нормальный результат поиска, а не сбой PHP.

Посчитать записи через безопасный цикл whileСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY, 1);
$it->rewind();
$count = 0;
while ($it->valid()) { $count++; $it->next(); }
echo $count, "\n";
Ожидаемый результат
2

Без next цикл оставался бы на одном элементе. valid не является обещанием, что исходная кеш-запись никогда не будет удалена конкурентным запросом.

Следующий инструмент: APCUIterator::current; APCUIterator::next.

APCUIterator::getTotalCountПолучить число записей по выбранным ключам.

APCu 5.0.0+ · APCu

APCUIterator::getTotalCount(): int

Получить число записей по выбранным ключам.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет; фильтр уже задан конструктором.
returnЦелое значение агрегата. Первый вызов любого getTotal* вычисляет сразу count/hits/size и сохраняет их в объекте.
ОбновлениеДля свежих значений создайте новый итератор. rewind не пересчитывает totals. Реализация 5.1.28 считает активные подходящие записи; это не отчёт об истории deleted-list.
Сводка по товарам без чужого разделаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY);
echo $it->getTotalCount(), "\n";
Ожидаемый результат
2

Фильтр применяется к ключам. Size включает внутреннее представление и служебные расходы записи, а hits — чтения из кеша, не число просмотров страницы целиком.

Отличить старую сводку объекта от нового состоянияСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$old = new APCUIterator('~^shop:~', APC_ITER_KEY);
$before = $old->getTotalCount(); // Заодно фиксируются hits и size.
apcu_store('shop:18', 'Пила');
$old->rewind();
$fresh = new APCUIterator('~^shop:~', APC_ITER_KEY);
echo $before, ':', $old->getTotalCount(), ':', $fresh->getTotalCount(), "\n";
Ожидаемый результат
1:1:2

Это общее правило всех трёх агрегатов. Если нужна текущая административная статистика, нельзя держать один объект и бесконечно перечитывать его сохранённую сводку.

Сбор агрегатов обходит подходящие записи и имеет стоимость. Не добавляйте его в каждый обычный запрос только потому, что он не возвращает большой массив.

Следующий инструмент: apcu_cache_info; apcu_sma_info; APCUIterator::__construct.

APCUIterator::getTotalHitsПолучить сумму попаданий в записи по выбранным ключам.

APCu 5.0.0+ · APCu

APCUIterator::getTotalHits(): int

Получить сумму попаданий в записи по выбранным ключам.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет; фильтр уже задан конструктором.
returnЦелое значение агрегата. Первый вызов любого getTotal* вычисляет сразу count/hits/size и сохраняет их в объекте.
ОбновлениеДля свежих значений создайте новый итератор. rewind не пересчитывает totals. Реализация 5.1.28 считает активные подходящие записи; это не отчёт об истории deleted-list.
Сводка по товарам без чужого разделаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY);
apcu_fetch('shop:17');
apcu_fetch('shop:17');
echo $it->getTotalHits(), "\n";
Ожидаемый результат
2

Фильтр применяется к ключам. Size включает внутреннее представление и служебные расходы записи, а hits — чтения из кеша, не число просмотров страницы целиком.

Отличить старую сводку объекта от нового состоянияСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$old = new APCUIterator('~^shop:~', APC_ITER_KEY);
$before = $old->getTotalCount(); // Заодно фиксируются hits и size.
apcu_store('shop:18', 'Пила');
$old->rewind();
$fresh = new APCUIterator('~^shop:~', APC_ITER_KEY);
echo $before, ':', $old->getTotalCount(), ':', $fresh->getTotalCount(), "\n";
Ожидаемый результат
1:1:2

Это общее правило всех трёх агрегатов. Если нужна текущая административная статистика, нельзя держать один объект и бесконечно перечитывать его сохранённую сводку.

Сбор агрегатов обходит подходящие записи и имеет стоимость. Не добавляйте его в каждый обычный запрос только потому, что он не возвращает большой массив.

Следующий инструмент: apcu_cache_info; apcu_sma_info; APCUIterator::__construct.

APCUIterator::getTotalSizeПолучить суммарную память записей в байтах по выбранным ключам.

APCu 5.0.0+ · APCu

APCUIterator::getTotalSize(): int

Получить суммарную память записей в байтах по выбранным ключам.

APCu хранит PHP-значения в памяти определённого экземпляра PHP, чтобы повторно использовать результат между подходящими запросами. Ключ — придуманное приложением имя, например shop:v1:catalog; значение — данные. Это ускоряющая копия: после очистки, вытеснения или перезапуска приложение должно уметь получить исходные данные заново.

Часть вызоваОбъяснение
ПараметрыНет; фильтр уже задан конструктором.
returnЦелое значение агрегата. Первый вызов любого getTotal* вычисляет сразу count/hits/size и сохраняет их в объекте.
ОбновлениеДля свежих значений создайте новый итератор. rewind не пересчитывает totals. Реализация 5.1.28 считает активные подходящие записи; это не отчёт об истории deleted-list.
Сводка по товарам без чужого разделаСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store(['shop:17' => 'Ключ', 'shop:18' => 'Пила', 'other:1' => 'Чужой раздел']);
$it = new APCUIterator('~^shop:~', APC_ITER_KEY);
var_dump($it->getTotalSize() > 0);
var_dump($it->getTotalSize() > strlen('Ключ') + strlen('Пила'));
Ожидаемый результат
bool(true)
bool(true)

Фильтр применяется к ключам. Size включает внутреннее представление и служебные расходы записи, а hits — чтения из кеша, не число просмотров страницы целиком.

Отличить старую сводку объекта от нового состоянияСамостоятельный пример
<?php
declare(strict_types=1);

apcu_store('shop:17', 'Ключ');
$old = new APCUIterator('~^shop:~', APC_ITER_KEY);
$before = $old->getTotalCount(); // Заодно фиксируются hits и size.
apcu_store('shop:18', 'Пила');
$old->rewind();
$fresh = new APCUIterator('~^shop:~', APC_ITER_KEY);
echo $before, ':', $old->getTotalCount(), ':', $fresh->getTotalCount(), "\n";
Ожидаемый результат
1:1:2

Это общее правило всех трёх агрегатов. Если нужна текущая административная статистика, нельзя держать один объект и бесконечно перечитывать его сохранённую сводку.

Сбор агрегатов обходит подходящие записи и имеет стоимость. Не добавляйте его в каждый обычный запрос только потому, что он не возвращает большой массив.

Следующий инструмент: apcu_cache_info; apcu_sma_info; APCUIterator::__construct.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.