Storage — API
new localzet\Storage\Client($servers) принимает строку адреса либо массив строк. Пустое значение вызывает Exception('Адрес хранилища пуст'). Соединение устанавливается не в конструкторе, а при первой команде.
| Метод | Ответ сервера | Особенности |
|---|---|---|
set($key, $value) | true | Создаёт или заменяет значение, в том числе null. |
get($key) | Значение либо null | Не различает отсутствие и сохранённое null. |
add($key, $value) | true / false | Записывает при !isset(); null не считается существующим значением. |
increment($key, $step = 1) | Новое число либо false | Не создаёт ключ. Нечисловое прежнее значение сбрасывается в ноль. |
cas($key, $oldValue, $newValue) | true / false | Сравнивает MD5 сериализованного старого значения. |
delete($key) | true | Возвращает true и при отсутствии ключа. |
Сетевые ошибки могут прервать любой метод исключением. Возвращаемые значения выше относятся к ответу корректно обработанной команды, а не к гарантии долговечности.
Доступ через свойства
Заголовок раздела «Доступ через свойства»$storage->example = 10;$value = $storage->example;$exists = isset($storage->example);unset($storage->example);Это оболочки над set/get/delete. isset() делает сетевой get() и проверяет, что ответ не равен null; отдельной операции exists нет. Magic-доступ может конфликтовать с публичными полями клиента timeout и pingInterval, поэтому для произвольных ключей используйте явные методы.
Настройки
Заголовок раздела «Настройки»| Поле | По умолчанию | Когда применяется |
|---|---|---|
timeout | 5 секунд | Установка соединения и настройка таймаута нового socket. |
pingInterval | 25 секунд | Регистрация ping-timer для нового соединения в CLI при наличии Timer. |
Публичного close(), настройки TLS, лимита размера ответа и отдельного read timeout в клиенте нет. Протокол не предоставляет идентификатора запроса, через который можно было бы безопасно повторить запись после обрыва связи.
new localzet\Storage\Server($ip = '0.0.0.0', $port = 8008)Создаёт localzet\Server с адресом frame://<ip>:<port>, одним worker и callback onMessage. Данные находятся в памяти объекта Storage Server. Не используйте default bind для недоверенной сети.
onMessage($connection, $buffer) получает уже декодированный Frame payload. Строка ping игнорируется без ответа. Остальные payload десериализуются и должны содержать cmd и key.
Формат обмена
Заголовок раздела «Формат обмена»TCP-сообщение состоит из четырёхбайтовой длины в network byte order и PHP-сериализованного payload. Длина включает сам заголовок:
uint32_be(4 + payload_length) | payloadНапример, клиентское тело команды записи:
[ 'cmd' => 'set', 'key' => 'article:42', 'value' => ['title' => 'Example'],]| Команда | Дополнительные поля |
|---|---|
get, delete | Нет. |
set, add | value. При отсутствии сервер использует null. |
increment | step. |
cas | md5 от serialize($oldValue) и новое value. |
Ответ — сериализованное значение в Frame-протоколе. Отсутствующий ключ читается как N;, успех записи — b:1;, отказ add/CAS — b:0;.
При отсутствии обязательных полей сервер закрывает соединение с bad request, при неизвестной команде — с bad cmd <command>. Клиентский read() просто десериализует ответ; эти строки не превращаются автоматически в исключения отдельного типа.
Граница доверия
Заголовок раздела «Граница доверия»Десериализация выполняется и сервером, и клиентом без allowed_classes => false. Контракт не предназначен для чужих payload, публичной API-ручки или хранения недоверенных сериализованных объектов. Фильтрация входа, аутентификация, ограничение размера и защищённый транспорт не реализованы этим пакетом.
Данные на одном сервере обрабатываются одним worker, но это не превращает несколько команд в атомарную транзакцию. Для конкурентного обновления одного значения используйте CAS с ограниченным числом повторов; межключевые инварианты требуют другого механизма.