Александр Некрасов · Автономное руководство

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

Разделы этой страницы
  1. System V IPC: сообщения, семафоры и общая память
  2. Когда нескольким обработчикам нужны общие данные
  3. Установка, три расширения, платформы и современные объекты
  4. Ёмкость, ini и ограничения операционной системы
  5. Не путать IPC ключ, ключ записи и тип сообщения
  6. Учебные файлы и безопасное владение ресурсами
  7. Резервирование: память для данных, семафор для порядка
  8. Полный каталог констант: флаги отдельно от errno
  9. Кто владеет ресурсом и что означает «освободить»
  10. Ошибки, стоимость и выбор альтернативы
  11. Проверить понимание на изменении требований
  12. Функции и методы этой темы
  13. Код и руководство с собой
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 130 · От переменных к нескольким процессам

System V IPC: сообщения, семафоры и общая память

Полный раздел SysV IPC: 19 функций, три служебных класса, все константы, установка и управление жизнью ресурсов.

Когда нескольким обработчикам нужны общие данные

На одном сервере работают два PHP обработчика: первый принимает заказ, второй делает импорт. Иногда им надо сообщить друг другу о задании, иногда — видеть один снимок состояния, иногда — по очереди менять общий остаток. Обычная переменная $stock одного процесса не становится общей для другого. System V IPC даёт три отдельных инструмента для этой ситуации: сообщения, память и семафоры.

Сервис склада: три разных действия
  1. Процесс сайта создал задание orderId=42
  2. Очередь передала задание обработчику
  3. Обработчик запросил пропуск у семафора
  4. Прочитал остаток A42=7 из общей памяти
  5. Записал A42=6 и вернул пропуск
ИнструментБытовая модель и её граница
Очередь сообщений (sysvmsg)Лоток с конвертами. Получение забирает конверт; тип позволяет выбрать нужный. Это не почта с автоматическим подтверждением обработки и хранением на диске.
Общая память (sysvshm)Шкаф с пронумерованными ячейками. Значение читается в локальную переменную; это не ссылка на общую PHP переменную и не база с транзакциями.
Семафор (sysvsem)Набор пропусков. При одном пропуске участники входят по очереди. Он не хранит бизнес-данные и не мешает коду, который вообще не попросил пропуск.

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

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

$storedStock = 7;
$workerARead = $storedStock;
$workerBRead = $storedStock;
$storedStock = $workerARead - 1;
$storedStock = $workerBRead - 1;
echo 'После двух резервирований: ', $storedStock, "\n";
echo "Ожидалось: 5\n";
Ожидаемый результат
После двух резервирований: 6
Ожидалось: 5

Это модель конкретного порядка событий, не тест потоков. Оба прочли 7; каждый получил 6; вторая запись затёрла первую. Защищать надо весь путь от чтения до записи.

Установка, три расширения, платформы и современные объекты

В официальной книге эти API объединены, но устанавливаются как три расширения. На Unix проверяют наличие SysV IPC у ОС и доступность в контейнере/namespace. При сборке PHP флаги --enable-sysvmsg, --enable-sysvsem, --enable-sysvshm включают соответствующие части. В пакетном дистрибутиве используйте его комплект расширений, совместимый с установленным PHP; имя пакета зависит от ОС. Старые упоминания PHP 3 configuration.h относятся к истории, а не к PHP 8.

Проверить возможности именно запущенного PHPПример для указанного окружения
<?php
declare(strict_types=1);

foreach (['sysvmsg', 'sysvsem', 'sysvshm'] as $extension) {
    echo $extension, ': ', extension_loaded($extension) ? 'есть' : 'нет', "\n";
}
echo 'sem_get: ', function_exists('sem_get') ? 'доступна' : 'недоступна', "\n";
Ожидаемый результат
Четыре строки с фактической доступностью расширений и sem_get.

Запустите в том SAPI, где работает приложение: CLI и PHP-FPM могут читать разные ini. Код не создаёт IPC ресурсы. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

sysvmsg и sysvsem не входят в обычную Windows сборку: для таких примеров нужен Unix/Linux, например отдельная учебная Linux среда. В PHP 8.5.11 существует Windows сборка sysvshm и реализация через mappings; это не обещание одинаковых Unix permissions/lifetime. Исполняемые shm примеры этой главы используют только новые приватные сегменты и завершают доступ в своём процессе. Ни наличие sysvshm, ни наличие shmop не означает наличие sem_get. shmop — другое расширение для байтов, его формат не совместим с PHP хранилищем переменных sysvshm.

Ресурсы PHP 4–7 заменены в PHP 8.0 объектами SysvMessageQueue, SysvSemaphore и SysvSharedMemory. Это не скрытое подключение к сети. Файловые права и контейнерные namespaces определяют, какие процессы видят один IPC ресурс. Две машины не разделяют такой сегмент: для нескольких серверов выбирайте сетевое хранилище/очередь с подходящим договором.

Ёмкость, ini и ограничения операционной системы

Настройка/лимитЧто проверять
sysvshm.init_memЕдинственная ini настройка этой книги: default 10000 байт, INI_SYSTEM. Используется при shm_attach без явного size. Не подменяется ini_set в обычном скрипте.
Явный sizeПоложительный размер нового сегмента. Служебный заголовок, сериализация и выравнивание занимают часть объёма. Existing segment не увеличится от повторного attach с большим size.
Unix общая памятьОграничения максимального/минимального размера, числа сегментов и общего объёма зависят от ОС/настроек. Старые SHMMAX/SHMMIN/SHMMNI/SHMSEG примеры документации — названия/исторические примеры, не универсальные современные числа.
СемафорыЛимиты количества наборов и разрешений. Утечки наборов приводят к системному отказу даже при небольшом PHP memory_limit.
ОчередиЛимит числа очередей, размера одного сообщения и суммарных байтов очереди. Это разные границы. msg_qbytes читается через stat и меняется с проверкой прав.

У sysvmsg/sysvsem нет пользовательских ini директив для снятия системных лимитов. Увеличение memory_limit PHP не увеличивает лимит очереди ОС. Сначала найдите утечку/медленного потребителя/неверный размер receive, затем обоснованно меняйте настройки среды. Не публикуйте phpinfo со всей конфигурацией на открытой странице.

Не путать IPC ключ, ключ записи и тип сообщения

В примерах есть три числа с разным смыслом. Системный key выбирает очередь/сегмент/набор; запись key=101 выбирает значение внутри общей памяти; message_type=2 выбирает вид сообщения. Ни одно из них не заменяет orderId=42 внутри данных. Совпадение чисел случайно: именуйте переменные по роли.

Три адреса в одном примере
  1. IPC key нашёл общую память приложения
  2. Внутри неё variable key 101 хранит массив остатков
  3. В очереди message type 2 означает reserve
  4. В JSON orderId 42 обозначает заказ магазина

Для independently launched участников ftok согласует ключ из защищённого файла, но не гарантирует уникальности. Владелец выбирает отдельный namespace/конфигурацию и режим доступа. Он не перебирает чужие key и не удаляет существующий ресурс «на всякий случай». Приватный key 0 удобен для автономного примера, но при каждом вызове создаёт независимый ресурс; повтор 0 в другом worker не является подключением к первому.

Учебные файлы и безопасное владение ресурсами

Каждый автономный пример поставляется со своими helper файлами. Они не подключаются к production, не выбирают произвольные внешние key и не удаляют чужие объекты. PHP исключение не отменяет finally; при аварийном завершении процесса Unix ресурсы всё равно могут требовать cleanup владельцем. В production supervisor хранит список именно своих ресурсов и проводит согласованное завершение; blanket ipcrm по всем объектам сервера недопустим.

Создать приватный сегмент для одного экспериментаПример для указанного окружения
<?php
function lessonMemory(int $size = 16384): SysvSharedMemory {
    $memory = shm_attach(0, $size, 0600);
    if ($memory === false) throw new RuntimeException('Не создан учебный сегмент');
    return $memory;
}
Ожидаемый результат
Файл объявляет lessonMemory(); сам по себе сегмент не создаёт.

Сохраните как ipc-memory.php. 0 — IPC_PRIVATE; созданный объект принадлежит вызвавшему примеру. Примеры всегда remove до detach, а Windows процесс завершает свои mapping handles. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Создать приватную очередь с явными правамиПример для указанного окружения
<?php
function lessonQueue(): SysvMessageQueue {
    // IPC_PRIVATE: create a queue belonging only to this example.
    $queue = msg_get_queue(0, 0600);
    if ($queue === false) throw new RuntimeException('Не создана очередь');
    // msg_get_queue first calls msgget(key, 0); for key 0 that already creates it.
    if (!msg_set_queue($queue, ['msg_perm.mode' => 0600])) {
        msg_remove_queue($queue);
        throw new RuntimeException('Не установлены права учебной очереди');
    }
    return $queue;
}
Ожидаемый результат
Файл объявляет lessonQueue(); сам по себе очередь не создаёт.

Сохраните как ipc-queue.php. Дополнительный set исправляет тонкость msg_get_queue(0): первая внутренняя попытка получения уже создаёт приватную очередь с нулевым mode. Владелец назначает 0600, затем пользуется очередью. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Создать приватный набор пропусковПример для указанного окружения
<?php
function lessonSemaphore(int $slots = 1): SysvSemaphore {
    if ($slots < 1) throw new InvalidArgumentException('Нужен хотя бы один пропуск');
    $semaphore = sem_get(0, $slots, 0600, true);
    if ($semaphore === false) throw new RuntimeException('Не создан семафор');
    return $semaphore;
}
Ожидаемый результат
Файл объявляет lessonSemaphore(); сам по себе набор не создаёт.

Сохраните как ipc-semaphore.php. Этот helper предназначен для изолированного опыта; совместные workers получают согласованный общий key, а не 0. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Резервирование: память для данных, семафор для порядка

Теперь соединим два инструмента на одном результате: резервирование двух товаров A42 должно оставить 5 из 7. Семафор выдаёт доступ, память хранит число. Обработчик сначала получает пропуск, потом читает, проверяет и записывает. Значение количества приходит в функцию аргументом; глобальная переменная здесь не нужна.

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

require __DIR__ . '/ipc-memory.php';
require __DIR__ . '/ipc-semaphore.php';
function reserve(SysvSharedMemory $memory, SysvSemaphore $lock, int $quantity): bool {
    if ($quantity < 1) throw new InvalidArgumentException('Количество должно быть положительным');
    if (!sem_acquire($lock, true)) throw new RuntimeException('Занято: повторить позже');
    try {
        if (!shm_has_var($memory, 101)) throw new RuntimeException('Остаток не инициализирован');
        $stock = shm_get_var($memory, 101);
        if (!is_int($stock) || $stock < 0) throw new RuntimeException('Повреждён остаток');
        if ($stock < $quantity) return false;
        if (!shm_put_var($memory, 101, $stock - $quantity)) throw new RuntimeException('Запись не удалась');
        return true;
    } finally { sem_release($lock); }
}
$memory = lessonMemory();
try {
    $lock = lessonSemaphore();
    try {
        if (!shm_put_var($memory, 101, 7)) throw new RuntimeException('Нет места');
        echo reserve($memory, $lock, 2) ? "Зарезервировано\n" : "Недостаточно товара\n";
        echo 'Осталось: ', shm_get_var($memory, 101), "\n";
    } finally { sem_remove($lock); }
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
Зарезервировано
Осталось: 5

Unix sysvsem + sysvshm. Это один контролируемый вызов с тем же lock, который должны разделять реальные участники. Для магазина с деньгами общая память сама по себе недостаточна: нужна долговечность и атомарная транзакция БД. Пример учит границе критического участка, не изображает готовую систему продаж. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Если quantity больше остатка, return false выполняется внутри try, но finally всё равно возвращает пропуск. Если функция уже вызвана из участка с удерживаемым тем же max=1 семафором, нельзя повторно захватывать его без специального протокола: разделите внешнюю координацию и внутреннее изменение. Захват нескольких locks в разном порядке создаёт deadlock; установите общий порядок и не допускайте вложенной неопределённости.

Полный каталог констант: флаги отдельно от errno

Все пять констант официальной книги относятся к сообщениям и доступны с sysvmsg. Два имени обозначают errno, три — флаги: подставлять errno в flags нельзя. Комбинируйте флаги побитовым |, а не логическим &&.

Константа (int)Роль
MSG_IPC_NOWAITФлаг receive: вернуть false сразу, если нет подходящего сообщения. Для send используется bool blocking=false, а не этот флаг.
MSG_EAGAINКод ошибки в выходном error_code, например очередь полна у неблокирующего send. Не флаг.
MSG_ENOMSGКод ошибки receive при отсутствии подходящего сообщения и NOWAIT. Не результат функции вместо bool.
MSG_NOERRORФлаг receive: при коротком max_message_size обрезать тело; остаток теряется. Для JSON/заказов обычно не подходит.
MSG_EXCEPTФлаг receive: при положительном selector выбрать первый отличающийся тип. Зависит от поддержки ОС.
Прочитать сообщение другого типа без ожиданияПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
msg_send($queue, 1, 'служебное', false, false, $error);
msg_send($queue, 2, 'заказ', false, false, $error);
$type = 0; $message = '';
$flags = MSG_IPC_NOWAIT | MSG_EXCEPT;
if (!msg_receive($queue, 1, $type, 1024, $message, false, $flags, $error)) {
    throw new RuntimeException('Не получено или MSG_EXCEPT не поддержан');
}
echo $type, ': ', $message, "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
2: заказ

На Unix с поддержкой MSG_EXCEPT. Отбрасывать ошибки лишь потому, что флаг существует в PHP, нельзя: поддержка системной операции тоже нужна. Сообщение типа 1 осталось в очереди до cleanup. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Кто владеет ресурсом и что означает «освободить»

ОперацияЧто происходит и чего не происходит
unset объекта очередиPHP теряет ручку; Unix очередь продолжает существовать.
msg_receiveУдаляет одно подходящее сообщение, не подтверждает выполнение бизнес-действия.
msg_remove_queueУдаляет очередь вместе с непрочитанными сообщениями для всех участников.
sem_releaseВозвращает захват данного объекта; набор остаётся.
sem_removeУдаляет весь системный набор; не повседневная разблокировка.
shm_remove_varУдаляет одну запись внутри сегмента.
shm_detachОтсоединяет свой view. На Unix не удаляет сегмент.
shm_removeНа Unix помечает целый сегмент к удалению; освобождение после последнего detach. Windows mapping lifetime отличается.

Общий ресурс может пережить HTTP запрос, поэтому не полагайтесь на PHP __destruct как на единственное место production cleanup. Аварийный kill/остановка хоста не гарантируют выполнение пользовательского кода. Очередь и память не являются долговечным журналом: перезагрузка/удаление/сбой могут потерять сведения. Восстанавливайте необходимые данные из надёжного источника, повторяйте действия по ID идемпотентно.

Ошибки, стоимость и выбор альтернативы

Измерять здесь надо не только длительность одной функции, но и ожидание, объём сериализации, длину очереди, пиковую память и долю повторов. Общая память не означает «нулевое копирование»: shm_get_var восстанавливает PHP структуру в процессе. В текущем sysvshm поиск записи идёт по хранимым блокам, а удаление сдвигает последующие данные; это не встроенный хеш-массив с гарантией постоянного времени по ключу. Большие часто заменяемые снимки могут оказаться дороже выбранного специализированного кеша.

СимптомПрактическое направление
sem_acquire не возвращаетсяНе держите ли уже max=1 lock; одинаковый ли порядок разных locks; вернули ли пропуск в finally; не делается ли долгий запрос внутри участка.
msg_send: EAGAINОчередь полна: сравните скорость producer/consumer, max size receive, необрабатываемый тип, лимит qbytes. Контролируемый повтор/отказ, не бесконечный цикл.
Сообщение не приходитВерный ли key/namespace/type и serialize договор; receive может ждать конкретный тип, пока другие уже есть.
shm_get_var вернул falseПроверьте наличие под тем же lock и договор типа; false может быть настоящим значением.
shm_put_var отказалРазмер сериализованного значения + накладные расходы, общий бюджет. Замена не гарантирует сохранение старого.
Call to undefined functionПроверить именно расширение/платформу/SAPI; sysvshm не предоставляет sem_get.

Если задача — один локальный файл, рассмотрите файловую блокировку и файловые операции. Для устойчивых заказов — транзакцию БД. Для нескольких серверов — сетевую очередь/хранилище с формальным договором доставки, подтверждения и отказа. Для передачи байтов/запросов между процессами — sockets. Выбор определяется свойствами задачи; утверждение «shared memory всегда быстрее базы» не учитывает синхронизацию и стоимость копирования.

Проверить понимание на изменении требований

Задание 1: в примере lost update поставьте read B после write A. Решение: B прочитает 6 и сохранит 5; семафор именно принуждает участников к такому порядку. Задание 2: сохраните false под 101. Решение: has=true, get=false; не трактуйте это как отсутствие. Задание 3: отправьте raw JSON, а на чтении включите unserialize. Решение: это несовпадающие форматы; исправьте договор обеих сторон, не замалчивайте ошибку.

Задание 4: большой пакет остаётся в очереди. Решение: определить максимальный допустимый размер сообщения и читать в рамках этого договора; не включать NOERROR для структурированного заказа. Задание 5: reserve вызывается дважды под одним захватом. Решение: один владелец критического участка вызывает внутреннюю функцию без повторного acquire; не превращайте max=1 в 2 лишь для обхода deadlock. Далее: функции и параметры по ссылке, JSON контракт, границы компонентов сервиса.

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

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

shm_attachОткрыть общую память для локальных обработчиков.

PHP 4+ · sysvshm

shm_attach(int $key, ?int $size = null, int $permissions = 0666): SysvSharedMemory|false

Открыть общую память для локальных обработчиков.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
keyСистемный ключ. 0 означает новый приватный сегмент. Одинаковый ненулевой ключ нужен участникам одного IPC договора.
sizeБайты при создании; null берёт sysvshm.init_mem, по умолчанию 10000. С PHP 8.0 допускается null.
permissionsПрава Unix при создании; 0666 разрешает чтение/запись всем пользователям, поэтому учебные примеры явно используют 0600.
Результат/отказОбъект с PHP 8.0; раньше resource. false и warning при системном отказе, ValueError при size < 1.
Путь действия: shm_attach
  1. key=0 → новый сегмент 16384 байта
  2. shm_put_var: запись 101 → 7
  3. shm_get_var: копия 7 в PHP
  4. remove + detach завершили владение

Представьте шкаф с пронумерованными ячейками: 101 содержит остаток 7. Другой процесс может обратиться к тому же шкафу. Но это не обычный PHP массив и не база данных: формат хранит сериализованные PHP значения, не имеет транзакций и требует согласованной блокировки. В минимальном примере ключ сегмента 0 создаёт отдельный учебный шкаф; 101 — совершенно другой ключ, номер записи внутри.

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

$memory = shm_attach(0, 16384, 0600);
if ($memory === false) throw new RuntimeException('Нет общей памяти');
try {
    if (!shm_put_var($memory, 101, 7)) throw new RuntimeException('Запись не удалась');
    echo shm_get_var($memory, 101), "\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
7

0 — приватный новый сегмент, 16384 — байты всего хранилища, 0600 — восьмеричные права владельца на Unix. Размер включает служебные данные и сериализацию. Код исполняется последовательно, конкурентных авторов нет.

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

try { shm_attach(0, 0, 0600); }
catch (ValueError $error) { echo "Размер должен быть положительным\n"; }
Ожидаемый результат
Размер должен быть положительным

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

Для процессов, запускаемых независимо, договоритесь о стабильном ключе через ftok и владельце жизненного цикла. Ключ 0 при каждом attach создаёт отдельный сегмент, поэтому два запуска с 0 не увидят данные друг друга. У существующего сегмента size/permissions не меняют его ёмкость и права. Подключение к случайному чужому ключу опасно: PHP ожидает свой формат и может инициализировать неподходящее содержимое. На Unix сегмент обычно переживает detach/завершение запроса; Windows реализация использует mappings и отличается по сроку жизни и правам.

Рядом: shm_put_var, shm_get_var, shm_remove, ftok.

shm_put_varПередать снимок PHP значения в общую память.

PHP 4+ · sysvshm

shm_put_var(SysvSharedMemory $shm, int $key, mixed $value): bool

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

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
shmПодключённый сегмент. После detach — Error.
keyЦелочисленный ключ записи внутри сегмента, не IPC ключ.
valueСериализуемое PHP значение. Повтор key заменяет запись.
Результатtrue записано; false и warning при нехватке места. Запись/замена не является транзакцией.
Путь действия: shm_put_var
  1. $stock содержит A42=7
  2. serialize внутри расширения
  3. байты записаны под 101
  4. изменение $stock не меняет записанное

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

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
$stock = ['A42' => 7, 'B17' => 3];
if (!shm_put_var($memory, 101, $stock)) throw new RuntimeException('Не сохранено');
$stock['A42'] = 99;
echo shm_get_var($memory, 101)['A42'], "\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
7

Запись — снимок, не привязка к $stock. Для публикации 99 требуется новая запись. Нет необходимости вручную serialize перед shm_put_var.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory(4096);
try {
    if (!shm_put_var($memory, 101, 'старый снимок')) throw new RuntimeException('Нет места');
    set_error_handler(static fn() => true, E_WARNING);
    try { $saved = shm_put_var($memory, 101, str_repeat('x', 20000)); }
    finally { restore_error_handler(); }
    echo $saved ? "Записано\n" : "Новый снимок не записан\n";
    echo shm_has_var($memory, 101) ? "Старый остался\n" : "Старого тоже нет\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
Новый снимок не записан
Старого тоже нет

В PHP 8.5.11 реализация удаляет старую запись перед проверкой места для новой. Это не транзакционная замена: нельзя обещать читателю сохранение старого снимка при false. Warning подавлен только вокруг намеренного отказа и результат всё равно проверен.

Ограничивайте объём, учитывайте накладные расходы и проверяйте bool. Для критичных данных используйте транзакционное хранилище; для снимков можно публиковать проверенную версию под новым ключом и переключать указатель под тем же семафором, но это самостоятельный протокол, не гарантия функции. Resource подключения, файловый descriptor и lock не переносятся как рабочие ресурсы. Сериализация объектов может вызывать методы и выбрасывать исключения; не допускайте посторонних писателей.

Рядом: shm_get_var, shm_has_var, shm_remove_var, sem_acquire.

shm_get_varПолучить обычное PHP значение из общей записи.

PHP 4+ · sysvshm

shm_get_var(SysvSharedMemory $shm, int $key): mixed

Получить обычное PHP значение из общей записи.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
shm/keyПодключение и целый ключ записи.
РезультатВосстановленное значение любого поддержанного типа; false может быть реальным значением.
ОтказыНет ключа/повреждение — warning и false; закрытое подключение — Error; hooks могут выбросить исключение.
Путь действия: shm_get_var
  1. В сегменте 101 → массив A42=7
  2. get создаёт PHP массив $stock
  3. локально уменьшаем до 6
  4. общая запись всё ещё 7

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

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 101, ['A42' => 7]);
$stock = shm_get_var($memory, 101);
$stock['A42']--;
echo $stock['A42'], ' / ', shm_get_var($memory, 101)['A42'], "\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
6 / 7

6 осталось в локальном массиве, 7 — в общей памяти. Прочитать → изменить → записать при нескольких авторах нужно под одним семафором на всём участке.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 102, false);
foreach ([102, 103] as $key) {
    if (!shm_has_var($memory, $key)) { echo "$key: отсутствует\n"; continue; }
    $value = shm_get_var($memory, $key);
    echo "$key: ", $value === false ? 'сохранён false' : 'другое', "\n";
}
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
102: сохранён false
103: отсутствует

Один процесс, поэтому между has/get никто не меняет состояние. При конкуренции эта пара нуждается в общей блокировке. Сравнение результата с false в одиночку неоднозначно.

Отсутствующий ключ даёт warning и false; повреждённая сериализация тоже может дать warning/false, а объектные hooks — исключение. Не используйте разрешение записи всем пользователям ради удобства: чтение PHP сериализации из недоверенного сегмента может создать объекты и запустить их методы. Большой массив полностью восстанавливается в памяти каждого читателя: общая память не отменяет выделение памяти PHP и стоимость разбора.

Рядом: shm_put_var, shm_has_var, sem_acquire.

shm_has_varУзнать, есть ли запись с заданным ключом.

PHP 5.3+ · sysvshm

shm_has_var(SysvSharedMemory $shm, int $key): bool

Узнать, есть ли запись с заданным ключом.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
keyЦелочисленный ключ записи.
Результатtrue существует, включая null/false; false отсутствует.
ГраницаСнимок текущего состояния, не блокировка. После detach — Error.
Путь действия: shm_has_var
  1. Запись 101 содержит null
  2. has(101) → true
  3. has(102) → false
  4. перед совместным get нужна синхронизация

Не каждый обработчик успел положить своё состояние. Проверка наличия помогает различить «ещё не вычислено» и сохранённые null/false. Она не резервирует запись и не запрещает соседу удалить её через мгновение.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 101, null);
echo shm_has_var($memory, 101) ? "101 существует\n" : "101 нет\n";
echo shm_has_var($memory, 102) ? "102 существует\n" : "102 нет\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
101 существует
102 нет

В отличие от isset обычного массива, shm_has_var видит существующую запись с null.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
foreach ([1, 2] as $attempt) {
    if (!shm_has_var($memory, 101)) {
        shm_put_var($memory, 101, 0);
        echo "Создан счётчик\n";
    } else { echo "Счётчик уже есть\n"; }
}
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
Создан счётчик
Счётчик уже есть

Два последовательных прохода показывают условие. Это ещё не конкурентный create-if-absent. Для реальных workers весь if и put защищаются одним общим семафором.

Рядом: shm_get_var, shm_put_var, sem_acquire.

shm_remove_varОсвободить одну запись, сохранив остальной сегмент.

PHP 4+ · sysvshm

shm_remove_var(SysvSharedMemory $shm, int $key): bool

Освободить одну запись, сохранив остальной сегмент.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
shm/keyПодключение и целый ключ удаляемой записи.
Результатtrue удалено; missing key — warning и false.
ГраницаНе уменьшает размер системного сегмента; освобождает место внутри него. Detached объект — Error.
Путь действия: shm_remove_var
  1. 101=импорт A, 102=импорт B
  2. remove_var(101)
  3. 101 нет, 102 доступна
  4. место 101 доступно новым записям

Импорт партии закончился: временная запись 101 больше не нужна, а соседняя 102 должна остаться. Удаляется только выбранное значение и освобождается место внутри PHP хранилища.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 101, 'импорт A');
shm_put_var($memory, 102, 'импорт B');
if (!shm_remove_var($memory, 101)) throw new RuntimeException('Не удалено');
echo shm_has_var($memory, 101) ? "A есть\n" : "A удалён\n";
echo shm_get_var($memory, 102), "\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
A удалён
импорт B

Сегмент продолжает работать. shm_remove_var не удаляет IPC ресурс целиком.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 101, 'готово');
foreach ([1, 2] as $attempt) {
    if (!shm_has_var($memory, 101)) { echo "Уже очищено\n"; continue; }
    if (!shm_remove_var($memory, 101)) throw new RuntimeException('Очистка не удалась');
    echo "Очищено\n";
}
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
Очищено
Уже очищено

Для отсутствующего ключа remove_var сам выдаёт warning и false. Здесь guard делает повторную последовательную очистку понятной; конкурентная проверка/удаление требует lock.

Рядом: shm_has_var, shm_put_var, shm_remove.

shm_detachЗакрыть своё подключение к общей памяти.

PHP 4+ · sysvshm

shm_detach(SysvSharedMemory $shm): true

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

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
shmЕщё подключённый объект.
РезультатС PHP 8.0 точный тип true; раньше bool.
ОшибкиПовторное detach либо работа через закрытый объект — Error.
Срок жизниОтсоединение не заменяет shm_remove на Unix. Не переносите Unix lifetime на Windows mappings без проверки.
Путь действия: shm_detach
  1. Обработчик прочитал 101
  2. detach закрывает его view
  3. общий Unix сегмент остаётся
  4. владелец удаляет после остановки всех участников

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

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try { shm_put_var($memory, 101, 7); }
finally {
    if (!shm_remove($memory)) throw new RuntimeException('Не отмечен к удалению');
    echo shm_detach($memory) ? "Подключение закрыто\n" : "Отказ\n";
}
Ожидаемый результат
Подключение закрыто

Владелец сначала помечает ресурс к удалению, пока ручка ещё действительна, затем отсоединяется. В обычном читателе общего Unix сегмента нужен только detach, удаление поручено владельцу.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
shm_remove($memory);
shm_detach($memory);
try { shm_has_var($memory, 101); }
catch (Error $error) { echo "Подключение уже закрыто\n"; }
Ожидаемый результат
Подключение уже закрыто

Сам объект переменной существует, но доступа к памяти уже нет. Это не проверяется через isset($memory).

Рядом: shm_attach, shm_remove.

shm_removeЗавершить жизнь системного сегмента после работы участников.

PHP 4+ · sysvshm

shm_remove(SysvSharedMemory $shm): bool

Завершить жизнь системного сегмента после работы участников.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
shmАктивная ручка сегмента, которым вы вправе управлять.
Результатtrue ОС приняла удаление; false с warning при отказе.
Ошибки/порядокDetached объект — Error. Сначала remove, потом detach; не наоборот.
UnixСуществующие attachment могут жить до detach; новые подключения и IPC_RMID зависят от ОС. Не строить переносимый протокол на подключении уже удалённого сегмента.
Путь действия: shm_remove
  1. Владелец прекращает новые задания
  2. Все workers завершены
  3. remove помечает сегмент
  4. последний detach освобождает Unix ресурс

Общий сегмент принадлежит приложению, а не каждому читателю. Команда завершения сервиса сначала останавливает новых участников, дожидается текущих и только затем удаляет ресурс. Иначе ещё работающий worker может потерять общий договор.

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

$memory = shm_attach(0, 16384, 0600);
if ($memory === false) throw new RuntimeException('Не создано');
try {
    echo shm_remove($memory) ? "Удаление запрошено\n" : "Удаление не удалось\n";
} finally { shm_detach($memory); }
Ожидаемый результат
Удаление запрошено

На Unix IPC_RMID помечает сегмент; фактическое освобождение после последнего detach. Пример не перебирает системные ключи и не затрагивает чужую память.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
shm_put_var($memory, 101, 'черновик');
shm_put_var($memory, 102, 'итог');
shm_remove_var($memory, 101);
echo shm_get_var($memory, 102), "\n";
echo "После чтения владелец завершит весь сегмент\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
итог
После чтения владелец завершит весь сегмент

В finally helper-примера вызываются remove и detach. До него запись 102 доступна; remove_var(101) не равнозначен remove($memory).

Рядом: shm_detach, shm_remove_var, shm_attach.

SysvSharedMemoryРучка подключённого сегмента, а не контейнер с публичными полями.

PHP 8.0+ · sysvshm

final class SysvSharedMemory

Ручка подключённого сегмента, а не контейнер с публичными полями.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
СозданиеТолько shm_attach, возможен false.
ИспользованиеПередавайте в shm_put_var/get_var/has_var и управление жизненным циклом.
ОграниченияНет пользовательского конструктора, сериализации, клонирования и динамических свойств.
Путь действия: SysvSharedMemory
  1. shm_attach → объект
  2. объект передан shm_get_var
  3. получен отдельный PHP массив
  4. detach инвалидирует подключение

Это непрозрачный служебный объект расширения, введённый вместо resource в PHP 8.0. У него нет пользовательских методов и свойств; расширение хранит подключение внутри. Класс final, нельзя наследовать, непосредственно конструировать или сериализовать.

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

require __DIR__ . '/ipc-memory.php';
$memory = lessonMemory();
try {
echo $memory instanceof SysvSharedMemory ? "Это ручка общей памяти\n" : "Другой тип\n";
} finally { shm_remove($memory); shm_detach($memory); }
Ожидаемый результат
Это ручка общей памяти

Проверять is_resource после обновления до PHP 8 неправильно. Объект передают в shm_* функции.

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

try { new SysvSharedMemory(); }
catch (Error $error) { echo "Используйте shm_attach\n"; }
Ожидаемый результат
Используйте shm_attach

new не знает ни key, ни size, ни правил ОС. Фабричная функция создаёт действительное подключение.

Рядом: shm_attach, shm_detach, shm_get_var.

msg_get_queueНайти либо создать очередь локальных сообщений.

PHP 4.3+ · sysvmsg

msg_get_queue(int $key, int $permissions = 0666): SysvMessageQueue|false

Найти либо создать очередь локальных сообщений.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
keyЦелый системный ключ; одинаковый ненулевой key связывает процессы в одном namespace. 0 создаёт приватную очередь.
permissionsВосьмеричные Unix права при создании. Не менять глобально на 0666 для обхода отказа.
РезультатSysvMessageQueue с PHP 8.0; раньше resource. false и warning при системном отказе.
Путь действия: msg_get_queue
  1. Сервис выбрал свой IPC ключ
  2. get вернул ручку очереди
  3. producer посылает заказ 42
  4. worker получает через ту же очередь

Производитель задания и обработчик должны найти одну очередь. Число key — адрес в IPC namespace ОС, не ID заказа. Для приложения можно получить его через ftok и хранить правила владения в конфигурации. Минимальные учебные примеры используют отдельную приватную очередь: каждый запуск создаёт свою и гарантированно удаляет её в finally.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$info = msg_stat_queue($queue);
if ($info === false) throw new RuntimeException('Нет состояния');
echo 'Заданий: ', $info['msg_qnum'], "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Заданий: 0

Файл ipc-queue.php входит в пример. Он создаёт key=0 и явно назначает права 0600. Особенность текущей реализации: первый msgget(0,0) уже создаёт приватную очередь без указанных прав; поэтому helper вызывает msg_set_queue до отправки. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

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

$key = ftok(__DIR__ . '/app.ipc', 'Q');
if ($key === -1 || $key === 0) throw new RuntimeException('Не получен общий ключ');
$queue = msg_get_queue($key, 0600);
if ($queue === false) throw new RuntimeException('Очередь недоступна');
echo $queue instanceof SysvMessageQueue ? "Очередь подключена\n" : "Ошибка\n";
// Worker does NOT remove the application's shared queue here.
Ожидаемый результат
Очередь подключена

Контекст: выделенный Unix IPC namespace приложения, файл app.ipc заранее создал владелец; владелец также отвечает за удаление очереди после остановки workers. Пример worker не вызывает remove при каждом завершении. Существующий ключ может обозначать чужой объект: ftok не даёт гарантии уникальности. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Если очередь существует, permissions не перенастраивают её. Если её нет, get создаёт очередь при достаточных правах; это не только «открыть существующую». Состояние и сообщения живут в ОС до удаления, даже когда объект PHP исчез. Лимиты на количество очередей и объём задаёт система. Смена ключа при каждом запросе без удаления приводит к накоплению ресурсов, а не к изоляции приложения.

Рядом: msg_send, msg_receive, msg_remove_queue, ftok.

msg_sendПередать задание в очередь и явно выбрать ожидание.

PHP 4.3+ · sysvmsg

msg_send(SysvMessageQueue $queue, int $message_type, mixed $message, bool $serialize = true, bool $blocking = true, &$error_code = null): bool

Передать задание в очередь и явно выбрать ожидание.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
queue/typeРучка очереди, положительное целое для категории сообщения.
message/serializetrue: PHP сериализация; false: сырая строка либо скаляр, превращаемый в строку.
blockingtrue ждёт при заполнении; false немедленно сообщает отказ.
error_code/результатtrue принято ОС, false отказ. При false errno записан в переданную переменную; MSG_EAGAIN может означать заполнение в nonblocking режиме.
Путь действия: msg_send
  1. orderId=42 → JSON строка
  2. send(type=2, raw, nowait)
  3. байты находятся в очереди
  4. receive → JSON decode → проверка

Чтобы попросить фоновый обработчик обновить остаток, передадим строку «заказ 42» сообщением типа 1. Тип — положительное целое для отбора сообщений; он не является PHP типом string/int. Сериализация — способ упаковать значение в байты; raw строка пригодна и для другой программы, PHP serialize — только для согласованных доверенных PHP участников.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
if (!msg_send($queue, 1, 'заказ 42', false, false, $error)) {
    throw new RuntimeException('Не отправлено, errno=' . $error);
}
$type = 0; $message = ''; $error = 0;
if (!msg_receive($queue, 1, $type, 1024, $message, false, MSG_IPC_NOWAIT, $error)) {
    throw new RuntimeException('Не получено');
}
echo $type, ': ', $message, "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
1: заказ 42

Первое false отключает PHP сериализацию, второе запрещает ждать заполненную очередь. $error — выходной аргумент по ссылке: функция сама записывает системный errno при отказе. Получатель использует соответствующее unserialize=false. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$job = ['orderId' => 42, 'action' => 'reserve'];
$json = json_encode($job, JSON_THROW_ON_ERROR);
$error = 0;
if (!msg_send($queue, 2, $json, false, false, $error)) {
    throw new RuntimeException($error === MSG_EAGAIN ? 'Очередь заполнена' : 'Ошибка отправки');
}
$type = 0; $payload = '';
if (!msg_receive($queue, 2, $type, 4096, $payload, false, MSG_IPC_NOWAIT, $error)) {
    throw new RuntimeException('Нет задания');
}
$received = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($received) || !is_int($received['orderId'] ?? null)) {
    throw new RuntimeException('Неверный контракт');
}
echo 'Обработать заказ ', $received['orderId'], "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Обработать заказ 42

JSON кодирует структуру в строку; msg_send передаёт байты, а не HTTP. Получатель проверяет поля после JSON разбора. При MSG_EAGAIN приложение сохраняет задание для контролируемого повтора либо честно возвращает занятость. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Обменяться массивом между доверенными PHP процессамиПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
if (!msg_send($queue, 1, ['orderId' => 42, 'quantity' => 2], true, false, $error)) {
    throw new RuntimeException('Массив не отправлен');
}
$type = 0; $job = null;
if (!msg_receive($queue, 1, $type, 4096, $job, true, MSG_IPC_NOWAIT, $error)) {
    throw new RuntimeException('Массив не получен');
}
if (!is_array($job) || !is_int($job['quantity'] ?? null)) throw new RuntimeException('Неверный контракт');
echo 'Количество: ', $job['quantity'], "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Количество: 2

Обе стороны согласовали PHP serialize/unserialize, поэтому ручного JSON разбора нет. Формат подходит только доверенным PHP участникам; разрешение посторонним писать сериализованные объекты недопустимо. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

С serialize=true по умолчанию можно передать массив: расширение сериализует его. В PHP 8.5 аргумент message фактически mixed для этого режима, хотя краткая таблица manual показывает скалярный union. При serialize=false допустимы string/int/float/bool, а массив вызывает TypeError. bool преобразуется в "1"/"0"; для межъязыкового договора лучше явно выбрать формат, а не полагаться на приведение. blocking=true ждёт свободного места; это может занять HTTP worker надолго. Максимальный размер одного сообщения и общая ёмкость очереди — разные лимиты. false сопровождается errno в выходном аргументе, а не значением MSG_EAGAIN вместо bool.

Рядом: msg_receive, msg_stat_queue, msg_set_queue.

msg_receiveИзвлечь подходящее сообщение с контролем размера и ожидания.

PHP 4.3+ · sysvmsg

msg_receive(SysvMessageQueue $queue, int $desired_message_type, &$received_message_type, int $max_message_size, mixed &$message, bool $unserialize = true, int $flags = 0, &$error_code = null): bool

Извлечь подходящее сообщение с контролем размера и ожидания.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
queue/desired_message_typeОчередь и правило отбора: 0, положительный или отрицательный selector.
received_message_type/messageПеременные для типа и тела полученного сообщения.
max_message_sizeПоложительный размер тела в байтах; переполнение без NOERROR оставляет сообщение.
unserialize/flagsВосстанавливать PHP значение либо вернуть binary-safe строку. NOWAIT не ждёт; EXCEPT инвертирует положительный тип; NOERROR обрезает.
Результат/errnobool. При отказе errno в error_code. MSG_ENOMSG — нет подходящего сообщения в NOWAIT.
Путь действия: msg_receive
  1. В очереди type3, type1, type2
  2. receive(-3) выбирает type1
  3. удаляет его из очереди
  4. сохраняет тип и текст в выходные переменные

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

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
foreach ([3 => 'обычное', 1 => 'срочное', 2 => 'среднее'] as $type => $text) {
    if (!msg_send($queue, $type, $text, false, false, $error)) throw new RuntimeException('Не отправлено');
}
$type = 0; $message = '';
if (!msg_receive($queue, -3, $type, 1024, $message, false, MSG_IPC_NOWAIT, $error)) {
    throw new RuntimeException('Нет подходящего сообщения');
}
echo $type, ': ', $message, "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
1: срочное

На Unix отрицательный selector -3 выбирает первый элемент наименьшего типа ≤ 3. Это не первое по времени сообщение любого типа ≤ 3. Частые приоритетные задания могут оттеснять обычные; нужна политика справедливости. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Не зависнуть, когда задания ещё не пришлиПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$type = 0; $message = null; $error = 0;
$received = msg_receive($queue, 0, $type, 4096, $message, false, MSG_IPC_NOWAIT, $error);
if (!$received && $error === MSG_ENOMSG) {
    echo "Сейчас нет заданий\n";
} elseif (!$received) { throw new RuntimeException('Ошибка очереди: ' . $error); }
else { echo "Получено задание\n"; }
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Сейчас нет заданий

MSG_ENOMSG находится в $error, возвращаемое значение функции — false. Не читайте старое значение $message после отказа и не крутите безостановочный busy loop. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Не потерять сообщение из-за короткого буфераПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
msg_send($queue, 1, 'ORDER-42', false, false, $error);
$type = 0; $message = '';
$short = msg_receive($queue, 1, $type, 3, $message, false, MSG_IPC_NOWAIT, $error);
echo $short ? "Прочитано\n" : "Буфер мал, сообщение остаётся\n";
if (!msg_receive($queue, 1, $type, 32, $message, false, MSG_IPC_NOWAIT, $error)) {
    throw new RuntimeException('Повторное чтение не удалось');
}
echo $message, "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Буфер мал, сообщение остаётся
ORDER-42

Без MSG_NOERROR слишком длинное сообщение не извлекается (E2BIG). Повтор с тем же малым буфером не поможет. С MSG_NOERROR хвост был бы отброшен навсегда: для JSON заказа такой режим неприемлем. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Аргумент selectorКакие сообщения выбираются
0Первое в очереди.
Положительный NПервое с типом N.
Отрицательный -NПервое с минимальным типом среди типов ≤ N.
N > 0 и MSG_EXCEPTПервое с типом, не равным N; поддержка зависит от системы.

received_message_type, message и error_code — выходные параметры: передают переменные, не литералы. max_message_size задаёт байты тела, без системного поля type; значение ≤ 0 вызывает ValueError. unserialize=true должно соответствовать send serialize=true; raw JSON читается с false. Доверяйте только своим сериализованным сообщениям: PHP объекты могут вызвать hooks. При ошибке десериализации сообщение уже извлечено, повтор receive его не восстановит. Успех обновляет last receiver PID/time и уменьшает msg_qnum.

Рядом: msg_send, msg_stat_queue, msg_remove_queue.

msg_queue_existsПроверить наличие очереди без создания.

PHP 5.3+ · sysvmsg

msg_queue_exists(int $key): bool

Проверить наличие очереди без создания.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
keyЗаранее согласованный IPC ключ приложения.
Результатtrue очередь найдена, false не найдена/системный вызов не смог её получить.
ОграничениеНе возвращает объект, не проверяет весь рабочий договор и не защищает от гонки.
Путь действия: msg_queue_exists
  1. ftok дал ключ приложения
  2. exists только проверяет
  3. другой процесс может поменять состояние
  4. операции всё равно проверяют свой результат

Для диагностики сервиса полезно узнать, есть ли уже очередь под согласованным ключом. Это проверка одного момента времени. Между проверкой и get другой процесс может удалить/создать её; поэтому exists не превращает get в атомарную операцию «открыть только старую».

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

$key = ftok(__DIR__ . '/app.ipc', 'Q');
if ($key === -1 || $key === 0) throw new RuntimeException('Ключ не получен');
echo msg_queue_exists($key) ? "Очередь уже есть\n" : "Очередь пока не найдена\n";
Ожидаемый результат
Очередь уже есть ИЛИ Очередь пока не найдена (зависит от стенда).

Только проверка согласованного ключа, без создания и удаления. false не доказывает, что у процесса достаточно прав, чтобы создать очередь. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

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

$key = ftok(__DIR__ . '/app.ipc', 'Q');
if ($key === -1 || $key === 0) throw new RuntimeException('Ключ не получен');
if (!msg_queue_exists($key)) { echo "Попросите владельца запустить сервис\n"; }
else {
    // An external shutdown may happen after the condition.
    echo "Нужны ещё проверки результатов get/send/receive\n";
}
Ожидаемый результат
Одна из двух диагностических строк в зависимости от состояния стенда.

В production выбранный supervisor управляет жизнью очереди; worker всё равно проверяет каждый вызов. Нельзя удалять очередь только потому, что она «уже существует». Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: msg_get_queue, ftok, msg_stat_queue.

msg_stat_queueПолучить счётчики и параметры очереди.

PHP 4.3+ · sysvmsg

msg_stat_queue(SysvMessageQueue $queue): array|false

Получить счётчики и параметры очереди.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
queueДействующая очередь.
РезультатМассив метаданных либо false при отказе.
ДинамикаСостояние меняется независимо от полученного массива.
Путь действия: msg_stat_queue
  1. send добавил заказ42
  2. qnum=1
  3. receive забрал заказ42
  4. qnum=0

Длина очереди помогает увидеть отставание обработчиков. Метаданные возвращаются обычным массивом с ключами вроде msg_qnum. Значения timestamp/PID меняются при работе; это диагностика, а не надёжное определение автора конкретного уже извлечённого сообщения при нескольких producers.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$error = 0;
msg_send($queue, 1, 'заказ 42', false, false, $error);
$before = msg_stat_queue($queue);
$type = 0; $message = '';
msg_receive($queue, 1, $type, 1024, $message, false, MSG_IPC_NOWAIT, $error);
$after = msg_stat_queue($queue);
if ($before === false || $after === false) throw new RuntimeException('Нет статистики');
echo $before['msg_qnum'], ' → ', $after['msg_qnum'], "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
1 → 0

При активных других workers счётчик может измениться сразу после чтения. Он не гарантирует успешность следующего receive. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$info = msg_stat_queue($queue);
if ($info === false) throw new RuntimeException('Нет состояния');
printf("Права: %04o\n", $info['msg_perm.mode'] & 0777);
echo $info['msg_qbytes'] > 0 ? "Ёмкость назначена ОС\n" : "Проверьте лимит\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Права: 0600
Ёмкость назначена ОС

msg_qbytes — ёмкость очереди в байтах, не длина текущего сообщения и не число элементов. Не зашиваем системный лимит в ожидаемый результат. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Все поляНазначение
msg_perm.uid / msg_perm.gidЧисловые UID/GID владельца.
msg_perm.modeБиты Unix доступа.
msg_stime / msg_rtime / msg_ctimeВремя последней отправки, приёма, изменения структуры.
msg_qnumЧисло сообщений, ожидающих чтения.
msg_qbytesМаксимальное число байтов в очереди.
msg_lspid / msg_lrpidPID последнего отправителя/получателя.

Рядом: msg_set_queue, msg_send, msg_receive.

msg_set_queueИзменить разрешённые параметры очереди владельцем.

PHP 4.3+ · sysvmsg

msg_set_queue(SysvMessageQueue $queue, array $data): bool

Изменить разрешённые параметры очереди владельцем.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
dataПоддержаны msg_perm.uid, msg_perm.gid, msg_perm.mode, msg_qbytes. Остальные поля не являются настройками.
ПраваНужны полномочия владельца/создателя либо соответствующие системные привилегии; смена UID/GID дополнительно ограничивается ОС.
ЛимитыПовышение msg_qbytes выше системного ограничения требует привилегий; не запускать весь PHP сайт как root.
Результатtrue применено; false отказ. Проверяйте stat после изменения при необходимости.
Путь действия: msg_set_queue
  1. Очередь принадлежит сервису
  2. data задаёт только mode/ёмкость
  3. ОС проверяет полномочия
  4. stat показывает применённый бюджет

Владелец сервиса задаёт доступ и бюджет очереди. Для этого передают массив только с изменяемыми полями. Не нужно копировать всю структуру stat и пытаться изменить счётчики сообщений или PID — они принадлежат ОС.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
if (!msg_set_queue($queue, ['msg_perm.mode' => 0600])) throw new RuntimeException('Нет прав');
$state = msg_stat_queue($queue);
if ($state === false) throw new RuntimeException('Нет состояния');
printf("Доступ %04o\n", $state['msg_perm.mode'] & 0777);
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Доступ 0600

0600 — запись в восьмеричной системе. Передача десятичного 600 означает другие биты. Разрешения регулируют доступ локальных пользователей, не сетевую авторизацию. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Уменьшить бюджет пустой учебной очередиПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
$state = msg_stat_queue($queue);
if ($state === false || $state['msg_qbytes'] < 1) throw new RuntimeException('Нет лимита');
$budget = min(1024, $state['msg_qbytes']);
if (!msg_set_queue($queue, ['msg_qbytes' => $budget])) throw new RuntimeException('Лимит не изменён');
$changed = msg_stat_queue($queue);
if ($changed === false) throw new RuntimeException('Нет состояния');
echo $changed['msg_qbytes'] === $budget ? "Бюджет применён\n" : "Проверьте ОС\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Бюджет применён

Пример не повышает системные лимиты и не требует root. Ограничение создаёт обратное давление; оно не исправляет медленный worker и не увеличивает лимит одного сообщения. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: msg_stat_queue, msg_get_queue, msg_send.

msg_remove_queueУдалить системную очередь и оставшиеся сообщения.

PHP 4.3+ · sysvmsg

msg_remove_queue(SysvMessageQueue $queue): bool

Удалить системную очередь и оставшиеся сообщения.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
queueРесурс, жизненным циклом которого вы управляете.
Результатtrue удалён; false при системном отказе, включая отсутствие/недостаточные права.
Побочный эффектВсе ожидающие сообщения удалены; blocked отправители/получатели получают ошибку от ОС.
Путь действия: msg_remove_queue
  1. Остановить producers
  2. Завершить/сохранить задания
  3. Дождаться workers
  4. владелец удаляет очередь

Удалять очередь следует после завершения всех её участников. Очередь вместе с непрочитанными сообщениями исчезает: это не аналог «закрыть своё подключение». Освобождение PHP переменной не удаляет очередь ОС.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try { echo "Эксперимент закончен\n"; }
finally {
    if (!msg_remove_queue($queue)) throw new RuntimeException('Очередь не удалена');
    echo "Очередь удалена владельцем\n";
}
Ожидаемый результат
Эксперимент закончен
Очередь удалена владельцем

В finally удаляется только очередь, созданная этим запуском с приватным ключом. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Увидеть, что удаление уничтожит ожидающее заданиеПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
    $error = 0;
    if (!msg_send($queue, 1, 'учебное задание', false, false, $error)) throw new RuntimeException('Не отправлено');
    $state = msg_stat_queue($queue);
    if ($state === false) throw new RuntimeException('Нет состояния');
    echo 'Будет потеряно сообщений: ', $state['msg_qnum'], "\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Будет потеряно сообщений: 1

Это специально созданное учебное сообщение. Для настоящей остановки решите заранее: дождаться обработки, сохранить задания или отменить их по явному договору; remove не сохраняет их автоматически. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: msg_get_queue, msg_stat_queue.

SysvMessageQueueНепрозрачная ручка очереди в PHP 8.

PHP 8.0+ · sysvmsg

final class SysvMessageQueue

Непрозрачная ручка очереди в PHP 8.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
Созданиеmsg_get_queue возвращает объект либо false.
ИспользованиеПередавайте в msg_send/receive/stat/set/remove.
ОграниченияНет пользовательских методов, конструктора, динамических свойств; объект не сериализуется и не клонируется.
Путь действия: SysvMessageQueue
  1. get нашёл очередь
  2. вернул SysvMessageQueue
  3. send получил эту ручку
  4. remove меняет жизнь ресурса для всех

Объект обозначает очередь ОС. У него нет метода send: отправка остаётся отдельной функцией msg_send($queue, ...). Он final, без публичного конструктора и сериализации; это конкретный способ расширения хранить системный descriptor, а не шаблон архитектуры вашего приложения.

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

require __DIR__ . '/ipc-queue.php';
$queue = lessonQueue();
try {
echo $queue instanceof SysvMessageQueue ? "Ручка очереди\n" : "Другой тип\n";
} finally { msg_remove_queue($queue); }
Ожидаемый результат
Ручка очереди

До PHP 8 использовался resource. Обновляйте проверки вместе с версией PHP. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Показать, почему нельзя вызвать newПример для указанного окружения
<?php
declare(strict_types=1);

try { new SysvMessageQueue(); }
catch (Error $error) { echo "Создавайте очередь через msg_get_queue\n"; }
Ожидаемый результат
Создавайте очередь через msg_get_queue

Здесь системный ресурс не создаётся. Получение валидной ручки требует ключа и проверки системного результата. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: msg_get_queue, msg_send, msg_remove_queue.

sem_getСоздать либо открыть набор пропусков для взаимного исключения.

PHP 4+ · sysvsem

sem_get(int $key, int $max_acquire = 1, int $permissions = 0666, bool $auto_release = true): SysvSemaphore|false

Создать либо открыть набор пропусков для взаимного исключения.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
keyСистемный ключ, 0 всегда создаёт новый приватный набор.
max_acquireМаксимум одновременно удерживаемых пропусков; 1 для mutex. Приложение должно отклонять значения < 1.
permissionsUnix права при создании.
auto_releaseАвтоматически освободить захваты этого объекта при завершении его жизни; с PHP 8.0 bool (ранее int).
РезультатSysvSemaphore с PHP 8.0; раньше resource. false и warning при системном отказе; проверяйте также результат acquire.
Путь действия: sem_get
  1. Вызов get создал один пропуск
  2. A acquire получил его
  3. B nowait получил false
  4. A release вернул пропуск

Остался один товар, и два обработчика хотят его зарезервировать. Если оба прочитают «1» до записи, оба решат, что товар доступен. Семафор — выдаваемый ОС пропуск в участок кода. При max_acquire=1 только один участник одновременно выполняет чтение, проверку и запись; все участники должны использовать тот же ключ и соблюдать правило.

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

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
if (!sem_acquire($semaphore, true)) throw new RuntimeException('Пропуск недоступен');
try { echo "Внутри защищённого участка\n"; }
finally { sem_release($semaphore); }
} finally { sem_remove($semaphore); }
Ожидаемый результат
Внутри защищённого участка

key=0 даёт новый приватный семафор; max_acquire=1, 0600 и auto_release=true переданы в helper. Один вызов get ещё ничего не блокирует: пропуск запрашивается через acquire. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Разрешить не более двух одновременных операцийПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(2);
try {
$held = 0;
try {
    for ($attempt = 1; $attempt <= 3; $attempt++) {
        if (sem_acquire($semaphore, true)) { $held++; echo "$attempt: пропуск\n"; }
        else { echo "$attempt: пока нет места\n"; }
    }
} finally {
    while ($held > 0) { sem_release($semaphore); $held--; }
}
} finally { sem_remove($semaphore); }
Ожидаемый результат
1: пропуск
2: пропуск
3: пока нет места

Один процесс последовательно занимает два доступных слота, чтобы показать счётчик без fork. Это ограничитель параллельности, не ограничитель запросов в секунду: для временного rate limit нужна другая логика. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Для независимых workers key должен быть одинаковым ненулевым и принадлежать вашему приложению. max_acquire задайте положительным и одинаковым у участников; не используйте sem_get для безопасной перенастройки активного пула. PHP использует набор из трёх системных семафоров, поэтому при взаимодействии с C нельзя подменить его произвольным набором из одного. auto_release=true возвращает захваченные этим объектом разрешения при его освобождении; это страховка, а не замена явному finally. Оно не удаляет системный набор.

Рядом: sem_acquire, sem_release, sem_remove, ftok.

sem_acquireПолучить пропуск перед операцией, которую нельзя выполнять одновременно.

PHP 4+ · sysvsem

sem_acquire(SysvSemaphore $semaphore, bool $non_blocking = false): bool

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

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
semaphoreРучка общего для участников набора.
non_blockingfalse ждёт разрешения, true возвращает управление сразу. Параметр появился в PHP 5.6.1.
Результатtrue получен пропуск; false занят в NOWAIT либо другая системная ошибка. При некоторых ошибках warning, errno параметра нет.
БалансКаждый успешный acquire требует release. false не следует «освобождать».
Путь действия: sem_acquire
  1. Проверить acquire=true
  2. прочитать текущие данные
  3. проверить и записать новое
  4. finally release

После acquire защищённым является только код, который все участники выполняют по одному договору. Если второй worker пишет в сегмент без acquire, семафор физически не запрещает ему запись. Поэтому lock охватывает всю операцию read → validate → modify → write, а не только последнюю строку.

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

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
if (!sem_acquire($semaphore, true)) throw new RuntimeException('Первый захват не удался');
try {
    if (!sem_acquire($semaphore, true)) echo "Занято: отложить действие\n";
    else { sem_release($semaphore); throw new RuntimeException('Неожиданный второй пропуск'); }
} finally { sem_release($semaphore); }
} finally { sem_remove($semaphore); }
Ожидаемый результат
Занято: отложить действие

При max=1 повторный блокирующий acquire этим же кодом ждал бы разрешения, которое сам код не успеет вернуть. Семафор не является рекурсивной блокировкой. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Вернуть пропуск даже при ошибке обработкиПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
if (!sem_acquire($semaphore, true)) throw new RuntimeException('Занято');
try {
    try { throw new RuntimeException('Неверная строка импорта'); }
    finally { sem_release($semaphore); }
} catch (RuntimeException $error) { echo "Ошибка разобрана\n"; }
if (!sem_acquire($semaphore, true)) throw new RuntimeException('Пропуск потерян');
try { echo "Следующий импорт может работать\n"; }
finally { sem_release($semaphore); }
} finally { sem_remove($semaphore); }
Ожидаемый результат
Ошибка разобрана
Следующий импорт может работать

Внешний catch отвечает за смысл ошибки, внутренний finally — за освобождение. Не удерживайте lock во время долгого HTTP запроса, если можно подготовить данные заранее и кратко опубликовать результат. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: sem_get, sem_release, shm_put_var.

sem_releaseВернуть ранее полученный пропуск.

PHP 4+ · sysvsem

sem_release(SysvSemaphore $semaphore): bool

Вернуть ранее полученный пропуск.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
semaphoreТот объект, который успешно приобрёл пропуск.
Результатtrue освобождён; false и обычно warning, если нет захвата/ресурс исчез/системный отказ.
ГраницаНе удаляет набор, не отменяет данные, уже записанные в критическом участке.
Путь действия: sem_release
  1. acquire уменьшил доступную ёмкость
  2. операция завершилась
  3. release увеличил ёмкость
  4. следующий worker получает пропуск

Возвращение пропуска позволяет следующему worker продолжить работу. Оно не удаляет системный семафор. Освобождать нужно тем объектом, которым выполнен успешный захват: расширение учитывает количество захватов каждого PHP объекта.

Разрешить следующую операциюПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
foreach (['импорт', 'отчёт'] as $operation) {
    if (!sem_acquire($semaphore, true)) throw new RuntimeException('Занято');
    try { echo $operation, "\n"; }
    finally {
        if (!sem_release($semaphore)) throw new RuntimeException('Пропуск не возвращён');
    }
}
} finally { sem_remove($semaphore); }
Ожидаемый результат
импорт
отчёт

Обе операции используют один набор. Они выполняются последовательно и не требуют создать новый семафор после release. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Распознать нарушение балансаПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
set_error_handler(static fn() => true, E_WARNING);
try { $released = sem_release($semaphore); }
finally { restore_error_handler(); }
echo $released ? "Освобождён\n" : "Нечего освобождать\n";
} finally { sem_remove($semaphore); }
Ожидаемый результат
Нечего освобождать

Намеренно не было acquire. Функция сообщает warning и false; перехватывается только ожидаемый warning в этом эксперименте. Release не является способом «на всякий случай разблокировать чужой процесс». Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: sem_acquire, sem_remove.

sem_removeУдалить системный набор после завершения всех участников.

PHP 4+ · sysvsem

sem_remove(SysvSemaphore $semaphore): bool

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

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
semaphoreНабор, которым вы вправе управлять.
Результатtrue удалён; false и warning при отсутствии/отказе прав/ошибке ОС.
ПоследствияРесурс исчезает для всех, ожидающие операции завершаются ошибкой. PHP переменная не становится автоматически null.
Путь действия: sem_remove
  1. Завершены новые и текущие задания
  2. каждый worker отпустил свои захваты
  3. владелец remove
  4. ключ свободен для другого жизненного цикла

После остановки всех обработчиков владелец приложения удаляет системный набор. После каждого HTTP запроса вызывать remove нельзя: соседи могут ждать/использовать тот же semaphore. Для повседневной работы нужен release, для окончательного завершения — remove.

Удалить частный учебный наборПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore();
try { echo "Участников больше нет\n"; }
finally {
    if (!sem_remove($semaphore)) throw new RuntimeException('Набор не удалён');
    echo "Набор удалён\n";
}
Ожидаемый результат
Участников больше нет
Набор удалён

Приватный key=0 гарантирует, что это ресурс текущего примера. Согласованный ненулевой key production удаляет только владелец после координации. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

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

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore();
try {
    if (!sem_acquire($semaphore, true)) throw new RuntimeException('Не захвачен');
    try { echo "Работа выполнена\n"; }
    finally { sem_release($semaphore); echo "Пропуск возвращён\n"; }
} finally { sem_remove($semaphore); echo "Учебный набор удалён\n"; }
Ожидаемый результат
Работа выполнена
Пропуск возвращён
Учебный набор удалён

В реальном сервисе владелец отдельно знает, что других workers больше нет. Только факт вашего release этого не доказывает. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: sem_get, sem_release.

SysvSemaphoreРучка набора и счётчик захватов данного PHP объекта.

PHP 8.0+ · sysvsem

final class SysvSemaphore

Ручка набора и счётчик захватов данного PHP объекта.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
СозданиеТолько sem_get, с PHP 8.0 объект вместо resource.
ДействияОтдельные sem_acquire/release/remove, не методы объекта.
Время жизниauto_release может вернуть захваты при освобождении объекта; не удаляет системный набор.
Путь действия: SysvSemaphore
  1. sem_get → объект
  2. acquire привязан к этому объекту
  3. release балансирует его захват
  4. remove — решение владельца ресурса

SysvSemaphore хранит связь с системным набором и баланс захватов данного объекта. Получение ещё одного PHP объекта с тем же key не является переносом этого баланса. Класс final, не имеет пользовательских методов и создаётся только sem_get.

Отличить ручку семафора от логического флагаПример для указанного окружения
<?php
declare(strict_types=1);

require __DIR__ . '/ipc-semaphore.php';
$semaphore = lessonSemaphore(1);
try {
echo $semaphore instanceof SysvSemaphore ? "Объект системного семафора\n" : "Другой тип\n";
echo "Сам факт существования объекта не означает захват\n";
} finally { sem_remove($semaphore); }
Ожидаемый результат
Объект системного семафора
Сам факт существования объекта не означает захват

Переменная true в обычном массиве процесса не заменяет согласованный межпроцессный semaphore. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Не создавать системную ручку через newПример для указанного окружения
<?php
declare(strict_types=1);

try { new SysvSemaphore(); }
catch (Error $error) { echo "Используйте sem_get\n"; }
Ожидаемый результат
Используйте sem_get

Нет публичного конструктора, сериализации, клонирования и динамических полей. Для собственного класса сервиса храните эту ручку в обычном свойстве и явно управляйте доступом. Контекстный пример для Unix CLI с указанными расширениями и разрешённым SysV IPC. Здесь проверен синтаксис; выполнение Unix IPC не заявляется.

Рядом: sem_get, sem_acquire, sem_release.

ftokСогласовать IPC ключ по известному файлу и метке проекта.

PHP 4.2+ · standard

ftok(string $filename, string $project_id): int

Согласовать IPC ключ по известному файлу и метке проекта.

IPC означает обмен между процессами одной операционной системы. Объект PHP здесь — ручка доступа к системному ресурсу, а не сами общие данные. Скобки в shm_get_var($memory, 101) передают сегмент и ключ записи; возвращённое значение можно сохранить в обычную переменную. Создание, использование, освобождение доступа и удаление ресурса — разные действия.

Сначала: три механизма и безопасный учебный стенд. Вспомнить: аргументы/return, массивы, try/finally. Для каждого примера ниже указано, нужен ли Unix со своим IPC namespace или доступно выполнение в текущем PHP.

ДоговорЧто это означает
filenameСуществующий доступный путь к одному и тому же файловому объекту у участников. Ограничения open_basedir учитываются.
project_idРовно один байт, обычно ASCII буква; не длинное имя приложения.
РезультатСистемный key либо -1 при отказе с warning. Пустой filename/неверная длина метки — ValueError в текущем PHP.
ГраницаНе выдаёт глобально уникальный ID, не создаёт очередь/сегмент и не резервирует key.
Путь действия: ftok
  1. app.ipc + Q
  2. ОС вычисляет key
  3. оба процесса используют этот key
  4. get/attach находят ресурс в общем namespace

Несколько запускаемых отдельно программ должны договориться о системном ключе. ftok получает его из существующего файла и однобайтовой метки проекта. Файл может быть пустым: важна его идентичность в файловой системе, а не текст внутри. Не используйте случайное число, если участники должны встретиться в одном IPC ресурсе.

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

$first = ftok(__DIR__ . '/app.ipc', 'Q');
$second = ftok(__DIR__ . '/app.ipc', 'Q');
if ($first === -1 || $second === -1) throw new RuntimeException('Ключ не получен');
echo $first === $second ? "Участники получили один ключ\n" : "Файл изменился\n";
Ожидаемый результат
Участники получили один ключ

Файл app.ipc приложен к примеру. Числовое значение зависит от ОС и файла, поэтому оно намеренно не зафиксировано. Замена файла новым может поменять key.

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

try { ftok(__DIR__ . '/app.ipc', 'QUEUE'); }
catch (ValueError $error) { echo "Нужна однобайтовая метка, например Q\n"; }
Ожидаемый результат
Нужна однобайтовая метка, например Q

В современном PHP project_id должен состоять ровно из одного байта. Буква кириллицы в UTF-8 занимает несколько байтов, поэтому используйте ASCII метку.

На Unix ftok сочетает ограниченные части device/inode и метки; уникальность не гарантируется. Один путь внутри разных контейнеров может указывать на разные файловые объекты, а одинаковый числовой key в разных IPC namespaces — на независимые ресурсы. Проверяйте результат -1 отдельно, а для общего ресурса отвергайте 0, означающий IPC_PRIVATE. Не преобразуйте key в unsigned «чтобы стал положительным»: системный key_t может иметь знаковое представление. В каталоге/файле, используемом для ключа, не должно быть посторонней записи.

Рядом: msg_get_queue, sem_get, shm_attach.

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

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

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

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

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