PHP-функции

OxPHP регистрирует свои функции через расширение oxphp_sapi, которое автоматически загружается для каждого PHP-скрипта, выполняемого сервером. Директива extension= и ручная загрузка не требуются. Все перечисленные здесь функции доступны с первой строки вашего PHP-кода.

Оглавление

oxphp_http_request()

php
oxphp_http_request(): \OxPHP\Http\Request

Возвращает объект запроса для текущего HTTP-запроса. Каждый вызов возвращает новый объект. Объект предоставляет типизированный доступ к HTTP-методу, URI, параметрам строки запроса, разобранному телу, заголовкам, cookie, загруженным файлам, IP клиента и таймингам запроса.

Возвращает: экземпляр \OxPHP\Http\Request, опирающийся на данные запроса в текущем PHP-потоке воркера.

Выбрасывает: исключение из пространства имён OxPHP\Http\Exception, если вызвана вне активного запроса:

Исключение Ситуация
\OxPHP\Http\Exception\WorkerIdleException Режим воркеров, между запросами
\OxPHP\Http\Exception\AsyncContextException Внутри колбэка oxphp_async()
\OxPHP\Http\Exception\NoActiveRequestException Любой другой контекст без активного запроса

В обычном коде обработки запроса обработка исключений не требуется.

Пример:

php
<?php $request = oxphp_http_request(); $method = $request->method(); // "POST" $path = $request->path(); // "/api/users" $email = $request->payload('email'); // from JSON or form body $token = $request->header('Authorization'); $theme = $request->cookie('theme', 'light');

Полный справочник по интерфейсу см. в документации HTTP Request API.

oxphp_superglobals_enabled()

php
oxphp_superglobals_enabled(): bool

Возвращает, включено ли заполнение суперглобальных переменных для этого экземпляра сервера. Значение отражает переменную окружения SUPERGLOBALS_ENABLED и не меняется в течение всего времени работы сервера.

Когда значение false, запрос выполняется с пустым $_GET, а $_SERVER содержит только четыре ключа, которые PHP регистрирует сам: REQUEST_TIME, REQUEST_TIME_FLOAT, argc и argv. $_POST, $_FILES и $_COOKIE формируются как обычно, потому что они берутся из тела запроса и заголовка Cookie, которых эта настройка не касается. Это не влияет на HTTP Object API (oxphp_http_request()), php://input и функции сессий PHP. Полная таблица приведена в разделе SUPERGLOBALS_ENABLED.

Возвращает: true, когда SUPERGLOBALS_ENABLED равно true (значение по умолчанию), иначе false.

Пример:

php
<?php if (oxphp_superglobals_enabled()) { $query = $_GET['page'] ?? 1; } else { $query = oxphp_http_request()->query('page', 1); }

oxphp_request_id()

php
oxphp_request_id(): string

Возвращает уникальный идентификатор текущего запроса. Это то же значение, что отправляется в заголовке ответа X-Request-ID. Если клиент присылает заголовок X-Request-ID, OxPHP пропускает его без изменений вместо генерации нового.

Возвращает: 20-символьную шестнадцатеричную строку, когда идентификатор генерирует OxPHP (например, "67890abc12341a2b0042"). Когда клиент присылает заголовок X-Request-ID, это значение возвращается как есть (1–64 символа, буквы и цифры плюс -, _, .).

Пример:

php
<?php $id = oxphp_request_id(); error_log("[$id] Processing order #1234"); // Propagate the ID to downstream services header("X-Correlation-ID: $id");

oxphp_worker_id()

php
oxphp_worker_id(): int

Возвращает индекс (отсчёт с нуля) PHP-потока воркера, обрабатывающего текущий запрос. Индексы воркеров находятся в диапазоне от 0 до PHP_WORKERS - 1.

Возвращает: целое число, идентифицирующее текущий поток воркера.

Пример:

php
<?php $workerId = oxphp_worker_id(); // Use per-worker temp files to avoid collisions $tmp = "/tmp/worker_{$workerId}_buffer.dat"; error_log("Worker $workerId handling request");

oxphp_server_info()

php
oxphp_server_info(): array

Возвращает ассоциативный массив с метаданными сервера и запроса.

Возвращает: массив со следующими ключами:

Ключ Тип Описание
version string Версия сервера (например, "0.13.0")
worker_id int То же значение, что и oxphp_worker_id()
request_time float Unix-метка времени с микросекундной точностью, когда начался запрос
worker_mode bool Работает ли текущий процесс в режиме воркеров
runtime_hooks array Категории хуков времени выполнения, которые этот процесс установил при запуске, в виде списка имён категорий (["sleep", "streams", "net"]). Пуст, если RUNTIME_HOOKS ничего не включила; см. Хуки времени выполнения

Пример:

php
<?php $info = oxphp_server_info(); // [ // "version" => "0.13.0", // "worker_id" => 3, // "request_time" => 1738800000.123456, // "worker_mode" => true, // "runtime_hooks" => ["sleep", "streams", "net"], // ] $elapsed = microtime(true) - $info['request_time']; echo "Processing took {$elapsed}s so far";

oxphp_finish_request()

php
oxphp_finish_request(): bool

Сбрасывает ответ клиенту и продолжает выполнение PHP в фоне. Клиент немедленно получает полный HTTP-ответ; скрипт продолжает работать, пока не завершится естественным образом. Это аналог fastcgi_finish_request() из PHP-FPM в OxPHP.

Возвращает: true при успехе, false, если функция уже была вызвана для этого запроса.

Note

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

Пример:

php
<?php http_response_code(202); echo json_encode(['status' => 'accepted']); oxphp_finish_request(); // The client already has its 202 response; continue working send_notification_email($user); update_analytics($event);

oxphp_is_worker()

php
oxphp_is_worker(): bool

Возвращает, работает ли сервер в режиме воркеров. Режим воркеров активируется, когда WORKER_MODE_ENABLED=true.

Возвращает: true, если сервер работает в режиме воркеров, false — в традиционном режиме.

Пример:

php
<?php if (oxphp_is_worker()) { // Reuse persistent connections across requests $db = $GLOBALS['db'] ??= new PDO($dsn); } else { // Traditional mode: create a new connection per request $db = new PDO($dsn); }

oxphp_worker()

php
oxphp_worker(callable $handler): bool

Входит в цикл постоянного режима воркеров. OxPHP вызывает $handler по одному разу для каждого входящего HTTP-запроса. Между запросами мягкий сброс очищает состояние на уровне запроса (буферы вывода, заголовки и суперглобальные переменные), не разрушая кучу PHP, поэтому любые переменные, объявленные вне обработчика, сохраняются между запросами. $_ENV намеренно исключён из этого сброса: при стандартном для PHP auto_globals_jit=1 он живёт всё время жизни воркера, поэтому значение, которое обработчик туда записал, прочитает каждый последующий запрос на этом воркере и любой запрос, мультиплексированный рядом с ним. См. Суперглобальные переменные.

Параметры:

  • $handler — вызывается по одному разу на запрос. Обработчик не получает аргументов. Используйте суперглобальные переменные ($_SERVER, $_GET, $_POST и т. д.) или oxphp_http_request() внутри обработчика для доступа к данным запроса.

Возвращает: true, когда цикл завершился, false, если сервер не в режиме воркеров. Каждый из перечисленных ниже выходов возвращает true, поэтому по значению нельзя понять, почему цикл завершился.

Цикл воркера завершается при выполнении любого из следующих условий:

  • Сервер корректно завершает работу
  • 3 запроса подряд завершаются аварийно. Обычная причина — фатальная ошибка в обработчике; учитываются также два вида сбоев вокруг файбера запроса. Необработанное исключение получает ответ и не считается, как и запрос, отменённый сервером, если только на нём не была зафиксирована ещё и фатальная ошибка (см. Режим воркеров → Перезапуск)
  • Воркер превышает WORKER_MAX_MEMORY_MIB
  • Запрос был завершён с вызовом внутренней функции на стеке, и после этого память воркера выросла сверх порога. Замер делается между двумя моментами, когда в обработке нет ни одного запроса, и не учитывает файберы, созданные воркером (см. Режим воркеров → Перезапуск)
  • Приложение вызывает Worker::scheduleExit()
  • Динамический пул (PHP_WORKERS=MIN:MAX) выводит этот воркер из работы, потому что тот простаивал дольше PHP_WORKERS_IDLE_SECONDS (по умолчанию 30), ничего не удерживая. Сервер продолжает обслуживать запросы: пул просто сокращается (см. Динамический пул)
Код после цикла — это завершение воркера

Код после oxphp_worker() выполняется при каждом из этих выходов, а не только при первом. В динамическом пуле это регулярное событие на исправном сервере: простаивающий воркер выводится из работы, выполняется его код завершения, а остальной пул продолжает обслуживать запросы. Пишите этот блок как завершение воркера, а не остановку сервера. Строка, которая пишет в лог «server stopping», ошибочна при каждом выходе, кроме последнего, а ресурс, общий не только для этого воркера, будет освобождён, пока сервер ещё работает.

Note

oxphp_worker() работает только в режиме воркеров (WORKER_MODE_ENABLED=true). В традиционном режиме она пишет предупреждение в лог и возвращает false.

Пример:

worker.php
<?php // worker.php — runs once per worker lifetime // Bootstrap: executed once on startup require __DIR__ . '/vendor/autoload.php'; $app = new App(); // Handle requests in a loop oxphp_worker(function () use ($app) { $app->handle(); }); // Reached when this worker's loop ends: server shutdown, recycling, // or a dynamic pool retiring this worker while the server keeps running $app->terminate();

oxphp_is_streaming()

php
oxphp_is_streaming(): bool

Возвращает, находится ли текущий запрос в потоковом режиме. Потоковый режим активируется при первом вызове oxphp_stream_flush() или автоматически, когда PHP устанавливает Content-Type: text/event-stream.

Возвращает: true, если потоковый режим активен, иначе false.

Пример:

php
<?php if (oxphp_is_streaming()) { echo "data: " . json_encode($event) . "\n\n"; oxphp_stream_flush(); } else { echo json_encode($allData); }

oxphp_stream_flush()

php
oxphp_stream_flush(): bool

Активирует потоковый режим и сбрасывает любой буферизованный вывод клиенту в виде HTTP-чанка. При первом вызове HTTP-заголовки отправляются немедленно и начинается потоковая передача. Каждый последующий вызов сбрасывает вывод, записанный со времени предыдущего сброса.

Возвращает: true при успехе, false, если oxphp_finish_request() уже была вызвана.

Note

Потоковый режим также активируется автоматически, когда PHP устанавливает Content-Type: text/event-stream. В этом случае можно использовать встроенную функцию PHP flush(), но сначала вызовите ob_end_flush(), чтобы обойти слой буферизации вывода PHP.

Пример:

php
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); for ($i = 0; $i < 10; $i++) { echo "id: $i\n"; echo "data: " . json_encode(['counter' => $i]) . "\n\n"; oxphp_stream_flush(); oxphp_sleep(1.0); // use oxphp_sleep instead of sleep — cooperative in fiber mode, where a switch is possible }

oxphp_sleep()

php
oxphp_sleep(float $seconds): void

Приостанавливает выполнение на указанную длительность. Внутри обработчика режима воркеров, выполняющегося в файбере, этот вызов кооперативен — он приостанавливает текущий файбер, чтобы во время ожидания могли обрабатываться другие запросы. Вне файбера он откатывается к стандартному блокирующему usleep().

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

  • внутри обработчика declare(ticks)
  • внутри диспетчеризации сигналов pcntl
  • пока формируются входные данные запроса
  • внутри FILTER_CALLBACK, вызванного из filter_input_array() с массивом определений
  • внутри обходов при завершении, которые запускают деструкторы после аварийного завершения запроса

Он также блокирует при вызове внутри файбера, запущенного пользовательским планировщиком (AMPHP, Revolt, голый new Fiber), потому что планировщик OxPHP не может возобновить такой контекст. В разделе Хуки времени выполнения описана та же граница для перехваченных нативных встроенных функций.

Не вытесняется RUNTIME_HOOKS

oxphp_sleep() кооперативна в режиме воркеров без всякой конфигурации и принимает дробные секунды. RUNTIME_HOOKS=sleep — отдельная, включаемая по желанию модернизация, которая заставляет кооперировать и нативные вызовы sleep()/usleep() (например, внутри стороннего кода), в тех же пределах. Она не отменяет необходимости в oxphp_sleep() в коде, который вы контролируете. См. Хуки времени выполнения.

Параметры:

  • $seconds — длительность приостановки в секундах. Допускаются дробные значения (например, 0.5 для 500 миллисекунд). Значения 0 или меньше возвращают управление немедленно.

Возвращает: void

Пример:

php
<?php oxphp_worker(function () { // In worker mode with fiber multiplexing: // this suspends the fiber rather than blocking the thread oxphp_sleep(1.0); echo json_encode(['done' => true]); });

oxphp_usleep()

php
oxphp_usleep(int $microseconds): void

Приостанавливает выполнение на указанное число микросекунд. Как и oxphp_sleep(), этот вызов кооперативен внутри файбера и в противном случае откатывается к блокирующему usleep(), в том числе в контекстах, перечисленных в разделе oxphp_sleep(), где переключение файбера запрещено или контекст не принадлежит OxPHP.

Параметры:

  • $microseconds — длительность приостановки в микросекундах. Значения 0 или меньше возвращают управление немедленно.

Возвращает: void

Пример:

php
<?php oxphp_worker(function () { // Poll for a condition every 100ms without blocking other requests while (!$condition_met()) { oxphp_usleep(100_000); } echo "ready"; });

oxphp_async()

php
oxphp_async(Closure $closure, mixed ...$args): int

Отправляет замыкание на выполнение в выделенном асинхронном потоке воркера и немедленно возвращает идентификатор промиса. Вызывающий код продолжает выполнение, не дожидаясь завершения замыкания. Используйте oxphp_async_await() для получения результата.

Параметры:

  • $closure — пользовательское Closure для выполнения в асинхронном потоке воркера
  • ...$args — аргументы, передаваемые замыканию. Принимаются скалярные значения (null, bool, int, float, string), массивы из них и экземпляры OxPHP\Shared\* (единственные объекты, которые могут пересекать границу потока). Ресурсы и любые объекты, не являющиеся Shared, отклоняются.

Возвращает: целочисленный идентификатор промиса. Передайте его в oxphp_async_await(), oxphp_async_await_all(), oxphp_async_await_race() или oxphp_async_await_any().

Выбрасывает: OxPHP\Async\AsyncException в следующих случаях:

  • Асинхронный пул отключён (ASYNC_WORKERS=0) — сообщение: "Async pool is disabled. Set ASYNC_WORKERS > 0 to enable."
  • Замыкание не является пользовательским
  • Асинхронный пул заполнен (все слоты очереди заняты)
  • Аргументы или переменные use содержат объекты или ресурсы
Note

Переменные, захваченные через use в замыкании, подчиняются тем же ограничениям — объекты и ресурсы отклоняются.

Пример:

php
<?php // Dispatch two independent tasks concurrently $p1 = oxphp_async(function () { return fetch_from_api('/users'); }); $p2 = oxphp_async(function () { return fetch_from_api('/posts'); }); // Retrieve both results $users = oxphp_async_await($p1); $posts = oxphp_async_await($p2);

oxphp_async_await()

php
oxphp_async_await(int $promise_id, float $timeout = 0.0): mixed

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

Параметры:

  • $promise_id — идентификатор промиса, возвращённый oxphp_async()
  • $timeout — максимальное время ожидания в секундах. 0.0 означает ждать бесконечно. По умолчанию: 0.0

Возвращает: возвращаемое значение асинхронного замыкания.

Выбрасывает:

  • OxPHP\Async\AsyncException, если асинхронный пул отключён (ASYNC_WORKERS=0) или если асинхронная задача выбросила исключение
  • OxPHP\Async\TimeoutException, если превышен $timeout

Пример:

php
<?php $promise = oxphp_async(function (int $n) { return array_sum(range(1, $n)); }, 1_000_000); $result = oxphp_async_await($promise); echo $result; // 500000500000 // With timeout try { $result = oxphp_async_await($promise, 5.0); } catch (\OxPHP\Async\TimeoutException $e) { echo "Task took too long"; }

oxphp_async_await_all()

php
oxphp_async_await_all(array $promise_ids, float $timeout = 0.0): array

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

Параметры:

  • $promise_ids — массив целочисленных идентификаторов промисов, возвращённых oxphp_async()
  • $timeout — максимальное время ожидания на каждый промис в секундах. 0.0 означает ждать бесконечно. По умолчанию: 0.0

Возвращает: ассоциативный массив, где каждый ключ — это идентификатор промиса (целое число), а каждое значение — результат этого промиса.

Выбрасывает:

  • OxPHP\Async\AsyncException, если асинхронный пул отключён (ASYNC_WORKERS=0) или если любой промис завершается с ошибкой
  • OxPHP\Async\TimeoutException, если любой промис превышает $timeout

Пример:

php
<?php $promises = [ oxphp_async(fn() => slow_query('users')), oxphp_async(fn() => slow_query('orders')), oxphp_async(fn() => slow_query('products')), ]; $results = oxphp_async_await_all($promises); foreach ($results as $promiseId => $result) { // process $result }

oxphp_async_await_race()

php
oxphp_async_await_race(array $promise_ids, float $timeout = 0.0): array

Устраивает гонку между несколькими промисами и возвращает первый разрешившийся, независимо от того, выполнился он или был отклонён. Остальные промисы не отменяются — они продолжают выполняться и остаются доступными для ожидания через oxphp_async_await(). Это аналог JavaScript Promise.race.

Параметры:

  • $promise_ids — массив как минимум из одного целочисленного идентификатора промиса, возвращённого oxphp_async(). Не должен быть пустым.
  • $timeout — максимальное время ожидания разрешения любого промиса в секундах. 0.0 означает ждать бесконечно. По умолчанию: 0.0

Возвращает: ассоциативный массив с двумя ключами:

  • id (int) — идентификатор промиса-победителя
  • value (mixed) — возвращаемое значение победившего промиса

Выбрасывает:

  • OxPHP\Async\AsyncException, если асинхронный пул отключён (ASYNC_WORKERS=0) или если победивший промис был отклонён
  • OxPHP\Async\TimeoutException, если ни один промис не разрешился в течение $timeout

Пример:

php
<?php // Try two mirror endpoints; use whichever responds first $p1 = oxphp_async(fn() => fetch('https://mirror-1.example.com/data')); $p2 = oxphp_async(fn() => fetch('https://mirror-2.example.com/data')); $winner = oxphp_async_await_race([$p1, $p2], timeout: 10.0); echo "Mirror {$winner['id']} won: " . json_encode($winner['value']);

oxphp_async_await_any()

php
oxphp_async_await_any(array $promise_ids, float $timeout = 0.0): array

Возвращает управление, как только один промис ВЫПОЛНЯЕТСЯ. Отклонения накапливаются и становятся наблюдаемыми только в том случае, если отклоняются все промисы. Это аналог JavaScript Promise.any — полезен для паттернов резервирования / избыточности, когда вам подходит любой работающий источник.

Параметры:

  • $promise_ids — массив как минимум из одного целочисленного идентификатора промиса, возвращённого oxphp_async(). Не должен быть пустым.
  • $timeout — максимальное время ожидания первого выполнения в секундах. 0.0 означает ждать бесконечно. По умолчанию: 0.0

Возвращает: ассоциативный массив с двумя ключами:

  • id (int) — идентификатор первого выполнившегося промиса
  • value (mixed) — возвращаемое значение победившего промиса

Выбрасывает:

  • OxPHP\Async\AsyncException, если асинхронный пул отключён (ASYNC_WORKERS=0)
  • OxPHP\Async\AggregateAsyncException, если отклонён каждый промис. Исключение переносит все ошибки через getErrors() (позиционные, с ключами 0..N-1), getErrorMap() (с ключами по id) и getPromiseIds().
  • OxPHP\Async\TimeoutException, если ни один промис не выполнился в течение $timeout. getPartialErrors() перечисляет промисы, которые уже были отклонены до дедлайна; getCancelledPromiseIds() перечисляет те, что не разрешились и поэтому были отменены. Для них устанавливается флаг отмены, а их приёмники сбрасываются — передача любого из этих идентификаторов в oxphp_async_await*() впоследствии выбрасывает "unknown or already-awaited promise id". Этот список — журнал аудита, а не очередь возобновляемой работы.

Поведение:

  • Промисы, которые всё ещё были в ожидании в момент победы, остаются доступными для ожидания по отдельности через oxphp_async_await().
  • Промисы, которые уже были отклонены до победителя, — нет: их результаты были потреблены при накоплении в качестве кандидатов-ошибок.

Пример:

php
<?php $mirror_a = oxphp_async(fn() => fetch('https://mirror-a.example.com/data')); $mirror_b = oxphp_async(fn() => fetch('https://mirror-b.example.com/data')); $mirror_c = oxphp_async(fn() => fetch('https://mirror-c.example.com/data')); try { $winner = oxphp_async_await_any([$mirror_a, $mirror_b, $mirror_c], 5.0); echo "Mirror {$winner['id']} responded: " . json_encode($winner['value']); } catch (\OxPHP\Async\AggregateAsyncException $e) { // every mirror rejected foreach ($e->getErrorMap() as $promise_id => $err) { error_log("mirror {$promise_id}: " . $err->getMessage()); } } catch (\OxPHP\Async\TimeoutException $e) { // deadline elapsed before any mirror fulfilled $partial = $e->getPartialErrors(); $cancelled = $e->getCancelledPromiseIds(); }

oxphp_register_decorator()

php
oxphp_register_decorator(string $class): bool

Регистрирует PHP-класс как декоратор, оборачивающий вызовы функций и методов. Класс должен реализовывать OxPHP\Decorator\AttributeInterface. После регистрации OxPHP вызывает хуки декоратора before() и after() вокруг каждого вызова функции или метода, который соответствует целям #[Attribute] декоратора.

Параметры:

  • $class — полное имя класса декоратора для регистрации

Возвращает: true при успехе, false, если класс не существует или не реализует OxPHP\Decorator\AttributeInterface.

Пример:

php
<?php use OxPHP\Decorator\AttributeInterface; use OxPHP\Decorator\Context; #[\Attribute(\Attribute::TARGET_METHOD)] class LogDecorator implements AttributeInterface { public function before(Context $ctx): void { error_log("Calling {$ctx->target} (request {$ctx->requestId})"); } public function after(Context $ctx): void { error_log("Finished {$ctx->target}"); } } // Register once at bootstrap (or worker startup) oxphp_register_decorator(LogDecorator::class);

oxphp_apm_trace()

php
oxphp_apm_trace(string $name, callable $callback, ?array $attributes = null): mixed

Выполняет колбэк внутри именованного спана. Спан открывается перед выполнением колбэка и закрывается после того, как колбэк вернёт управление или выбросит исключение, поэтому вызывать oxphp_apm_end() не нужно.

Колбэк получает локальный ID спана единственным аргументом. Передайте его в oxphp_apm_attribute(), oxphp_apm_event() или oxphp_apm_status(), чтобы явно адресовать этот спан, а не тот, что является текущим.

Если колбэк выбрасывает исключение, спан помечается как ошибочный и на нём записывается событие exception с exception.type и exception.message, после чего исключение пробрасывается дальше без изменений. exception.stacktrace не записывается: его сбор стоит повторного входа в PHP при каждом выбросе, а этот путь срабатывает гораздо чаще, чем oxphp_apm_error(). Если стектрейс нужен, вызовите oxphp_apm_error($e) явно.

Когда APM отключён (OTEL_APM_ENABLED не задана или имеет ложное значение; принимаются on, true, 1 и yes без учёта регистра), колбэк всё равно выполняется и его возвращаемое значение всё равно передаётся дальше. В качестве ID спана он получает 0, и ничего не записывается.

Если $callback не является вызываемым, выбрасывается TypeError. Если же при его разрешении возникает собственное исключение (автозагрузчик, который выбрасывает исключение на строке 'Class::method', или обработчик ошибок, который выбрасывает исключение на уведомление об устаревании для строки 'self::method'), это исключение пробрасывается как есть, и колбэк не выполняется.

Параметры:

  • $name — имя спана
  • $callback — вызываемый объект для выполнения внутри спана; получает int $span_id
  • $attributes — необязательный ассоциативный массив строковых пар ключ-значение атрибутов

Возвращает: mixed — значение, которое вернул $callback.

Пример:

php
<?php $user = oxphp_apm_trace('user.fetch', function (int $span) use ($id) { oxphp_apm_attribute('user.id', (string) $id, $span); return User::find($id); }, ['db.system' => 'mysql']);

oxphp_apm_start()

php
oxphp_apm_start(string $name, ?array $attributes = null): int

Открывает новый спан и возвращает локальный идентификатор для последующих ссылок. Спан становится дочерним по отношению к текущему активному спану (или к корневому спану запроса, если ни один спан не активен). Используйте oxphp_apm_end(), чтобы закрыть его.

Параметры:

  • $name — имя спана (например, "cache.warm", "payment.process")
  • $attributes — необязательный ассоциативный массив строковых пар ключ-значение атрибутов, устанавливаемых на спан при создании

Возвращает: целочисленный локальный идентификатор спана. Передайте его в oxphp_apm_end(), oxphp_apm_attribute() или другие функции, принимающие $span_id. Возвращает 0, когда APM отключён.

Пример:

php
<?php $spanId = oxphp_apm_start('order.validate', [ 'order.type' => 'subscription', ]); validateOrder($order); oxphp_apm_end($spanId);

oxphp_apm_end()

php
oxphp_apm_end(int $span_id): void

Закрывает спан, открытый функцией oxphp_apm_start(). Записывается время завершения спана, и он перемещается из активного стека в список завершённых, готовый к экспорту.

Параметры:

  • $span_id — локальный идентификатор спана, возвращённый oxphp_apm_start()

Возвращает: void

Note

Всегда закрывайте спаны в обратном порядке. Если вы открыли спан A, затем спан B, закройте B перед A. Незакрытые спаны автоматически закрываются в конце запроса и помечаются oxphp.span.leaked=true.

oxphp_apm_attribute()

php
oxphp_apm_attribute(string $key, mixed $value, ?int $span_id = null): void

Устанавливает атрибут ключ-значение на спане. Значения преобразуются в строки. Если $span_id не указан, атрибут добавляется к текущему активному спану.

Параметры:

  • $key — ключ атрибута (например, "user.id", "cache.hit")
  • $value — значение атрибута (string, int, float, bool или null -- преобразуется в строку)
  • $span_id — необязательный локальный идентификатор спана. Если опущен, нацеливается на текущий спан

Возвращает: void

Пример:

php
<?php $spanId = oxphp_apm_start('db.query'); oxphp_apm_attribute('db.system', 'mysql'); oxphp_apm_attribute('db.statement', 'SELECT * FROM users WHERE id = ?'); oxphp_apm_attribute('db.row_count', $rowCount, $spanId); oxphp_apm_end($spanId);

oxphp_apm_event()

php
oxphp_apm_event(string $name, ?array $attributes = null, ?int $span_id = null): void

Записывает событие с меткой времени на спане. События полезны для логирования отдельных происшествий в течение жизни спана (например, промах кэша, попытка повтора, проверка авторизации).

Параметры:

  • $name — имя события (например, "cache.miss", "retry")
  • $attributes — необязательный ассоциативный массив строковых пар ключ-значение атрибутов события
  • $span_id — необязательный локальный идентификатор спана. Если опущен, нацеливается на текущий спан

Возвращает: void

Пример:

php
<?php $spanId = oxphp_apm_start('payment.process'); oxphp_apm_event('payment.authorized', [ 'provider' => 'stripe', 'amount' => '49.99', ]); oxphp_apm_end($spanId);

oxphp_apm_error()

php
oxphp_apm_error(mixed $exception, ?int $span_id = null): void

Помечает статус спана как ошибку (код статуса 2). Используйте это для того, чтобы отметить спаны, где произошло исключение или сбой.

Параметры:

  • $exception — исключение или ошибка (используется для контекста; статус устанавливается независимо от типа)
  • $span_id — необязательный локальный идентификатор спана. Если опущен, нацеливается на текущий спан

Возвращает: void

Пример:

php
<?php $spanId = oxphp_apm_start('external.api'); try { $result = callExternalApi(); } catch (\Throwable $e) { oxphp_apm_error($e, $spanId); throw $e; } finally { oxphp_apm_end($spanId); }

oxphp_apm_status()

php
oxphp_apm_status(int $code, ?string $description = null, ?int $span_id = null): void

Устанавливает код статуса и необязательное описание на спане.

Параметры:

  • $code — код статуса: 0 = Unset, 1 = Ok, 2 = Error
  • $description — необязательное человекочитаемое описание статуса
  • $span_id — необязательный локальный идентификатор спана. Если опущен, нацеливается на текущий спан

Возвращает: void

Пример:

php
<?php $spanId = oxphp_apm_start('validation'); if ($valid) { oxphp_apm_status(1, 'Validation passed', $spanId); } else { oxphp_apm_status(2, 'Invalid input: missing email', $spanId); } oxphp_apm_end($spanId);

oxphp_apm_trace_id()

php
oxphp_apm_trace_id(): string

Возвращает W3C trace ID (32 шестнадцатеричных символа) для контекста трассировки текущего запроса. Это то же значение, что и $_SERVER['OXPHP_TRACE_ID'], доступное без суперглобальных переменных.

Возвращает: 32-символьную шестнадцатеричную строку trace ID. Возвращает пустую строку, когда APM отключён или контекст трассировки не активен.

Пример:

php
<?php $traceId = oxphp_apm_trace_id(); error_log("Processing request in trace {$traceId}");

oxphp_apm_span_id()

php
oxphp_apm_span_id(): string

Возвращает span ID (16 шестнадцатеричных символов) текущего активного спана. Если есть вложенные спаны, возвращается идентификатор самого внутреннего открытого спана.

Возвращает: 16-символьную шестнадцатеричную строку span ID. Возвращает пустую строку, когда ни один спан не активен.

oxphp_apm_header()

php
oxphp_apm_header(): string

Возвращает значение W3C-заголовка traceparent для текущего контекста спана. Используйте это для передачи контекста трассировки в нижестоящие HTTP-вызовы.

Возвращает: строку в формате 00-{trace_id}-{span_id}-01. Возвращает пустую строку, когда контекст трассировки не активен.

Пример:

php
<?php $spanId = oxphp_apm_start('http.call'); $traceparent = oxphp_apm_header(); $response = file_get_contents('https://api.example.com/data', false, stream_context_create([ 'http' => [ 'header' => "traceparent: {$traceparent}\r\n", ], ]) ); oxphp_apm_end($spanId);

OxPHP\Profile\is_active()

php
OxPHP\Profile\is_active(): bool

Возвращает true, когда захват профиля в данный момент активен для этого запроса — то есть его включил триггер (заголовок, cookie, параметр строки запроса или частота сэмплирования) или скрипт вызвал start(), а захват не приостановлен через pause() или stop(). При выключенном профилировщике (PROFILER_ENABLED) триггеры не проверяются, а start() ничего не делает, так что ни то ни другое захват не включает.

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

Возвращает: bool.

Пример:

php
<?php if (OxPHP\Profile\is_active()) { OxPHP\Profile\mark('checkpoint.before_query'); }

OxPHP\Profile\start()

php
OxPHP\Profile\start(): void

Программно включает захват профиля до конца текущего запроса, даже если ни один триггер не сработал на RINIT. Устанавливает режим профилирования в PROFILE_ALL и снимает флаг приостановки.

Ничего не делает, пока профилировщик выключен (PROFILER_ENABLED): тогда профилировщик не записывает вызовы функций, поэтому вызов не включает захват и не заставляет is_active() возвращать true.

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

Возвращает: void.

Пример:

php
<?php if ($request->header('x-debug') === 'on') { OxPHP\Profile\start(); }

OxPHP\Profile\stop()

php
OxPHP\Profile\stop(): void

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

Возвращает: void.

Пример:

php
<?php OxPHP\Profile\start(); expensive_work(); OxPHP\Profile\stop(); non_profiled_work();

OxPHP\Profile\pause()

php
OxPHP\Profile\pause(): void

Мягкий вариант stop(). Эффект тот же (устанавливает флаг приостановки); различие в намерении — pause() сигнализирует, что захват возобновится позже через resume(), тогда как stop() — нет.

Возвращает: void.

OxPHP\Profile\resume()

php
OxPHP\Profile\resume(): void

Снимает флаг приостановки, установленный pause() или stop(). Сам режим профиля при этом не меняется — если он никогда не был включён, resume() не делает ничего наблюдаемого.

Возвращает: void.

Пример:

php
<?php OxPHP\Profile\pause(); $secret = decrypt_payload($data); OxPHP\Profile\resume();

OxPHP\Profile\mark()

php
OxPHP\Profile\mark(string $label, ?array $attrs = null): void

Прикрепляет событие Mark к самому верхнему открытому спану, с необязательным набором атрибутов. Ничего не делает, когда нет открытого спана (например, профилирование не активно, или mark() вызвана на верхнем уровне запроса вне какого-либо инструментированного фрейма).

Ключи и значения атрибутов приводятся к строкам; нестроковые значения становятся пустой строкой.

Параметры:

  • $label — короткое человекочитаемое имя события (например, "cache.miss", "db.slow_query")
  • $attrs — необязательный array<string, scalar> пар ключ/значение, прикрепляемых к событию

Возвращает: void.

Пример:

php
<?php function load_user(int $id): array { $cached = $cache->get("user:$id"); if ($cached === null) { OxPHP\Profile\mark('cache.miss', ['key' => "user:$id"]); $cached = $db->fetchUser($id); } return $cached; }

OxPHP\Profile\metric()

php
OxPHP\Profile\metric(string $name, float $value): void

Добавляет атрибут metric.<name> к текущему открытому спану. Ничего не делает, когда нет открытого спана.

В отличие от mark() (которая создаёт отдельное событие), metric() записывает данные в набор атрибутов существующего спана — полезно для фиксации числовых наблюдений, привязанных к окружающей операции (число полученных строк, обработанных байтов, количество повторов).

Параметры:

  • $name — идентификатор метрики; будет сохранён как metric.<name>
  • $value — числовое значение (приводится к float)

Возвращает: void.

Пример:

php
<?php function search(string $query): array { $results = $index->search($query); OxPHP\Profile\metric('result_count', count($results)); return $results; }

Классы и интерфейсы

Расширение oxphp_sapi регистрирует следующие классы:

HTTP

Класс Описание
OxPHP\Http\Request Объект запроса, возвращаемый oxphp_http_request(). final — не может быть расширен.
OxPHP\Http\Attributes Изменяемый контейнер атрибутов запроса (для middleware). final.
OxPHP\Http\Session Объект сессии, доступный через $request->session(). final.
OxPHP\Http\UploadedFile Объект загруженного файла из $request->files(). final.

Декораторы

Класс / интерфейс Описание
OxPHP\Decorator\AttributeInterface Интерфейс для декораторов. Требует методов before(Context $ctx) и after(Context $ctx).
OxPHP\Decorator\Context Контекстный объект, передаваемый хукам декоратора. final. Публичные свойства: target, class, method, function, objectId, requestId, traceId. Методы: getParams(): array, getResult(): mixed, hasResult(): bool. Полный справочник см. в Декораторы.

Трассировка

Класс Описание
OxPHP\Apm\Trace Встроенный атрибут для автоматического создания спанов. Применяется к функциям или методам.

Async

Класс Описание
OxPHP\Async\BorrowedProxy Прокси-объект для одолженных значений между потоками.

Исключения

Все исключения, регистрируемые расширением:

Исключение Расширяет Когда выбрасывается
OxPHP\Async\AsyncException \Exception Ошибка в асинхронной задаче (oxphp_async_await()) или недопустимые аргументы в oxphp_async()
OxPHP\Async\TimeoutException OxPHP\Async\AsyncException Превышен таймаут в любой из oxphp_async_await(), oxphp_async_await_all(), oxphp_async_await_race() или oxphp_async_await_any(). Для таймаутов oxphp_async_await_any() заполняются аксессоры getPartialErrors(): array<int, \Throwable> и getCancelledPromiseIds(): list<int>; для остальных мест вызова оба возвращают [].
OxPHP\Async\AggregateAsyncException OxPHP\Async\AsyncException Выбрасывается oxphp_async_await_any(), когда отклонён каждый промис. Методы: getErrors(): list<\Throwable> (позиционные, с ключами 0..N-1 по позиции во входных данных), getErrorMap(): array<int, \Throwable> (с ключами по id промиса), getPromiseIds(): list<int> (входные id промисов по порядку).
OxPHP\Async\BorrowException \Exception Ошибка при одалживании значения между потоками
OxPHP\Http\Exception\NoActiveRequestException \RuntimeException Вызов oxphp_http_request() вне активного запроса
OxPHP\Http\Exception\AsyncContextException NoActiveRequestException Вызов oxphp_http_request() внутри колбэка oxphp_async()
OxPHP\Http\Exception\WorkerIdleException NoActiveRequestException Вызов oxphp_http_request() в режиме воркеров между запросами
OxPHP\Decorator\RejectedException \Exception Декоратор отклонил вызов функции/метода

Проверка расширения

Вы можете проверить, что расширение OxPHP загружено, и просмотреть все зарегистрированные функции:

php
<?php if (extension_loaded('oxphp_sapi')) { echo "OxPHP extension is loaded\n"; } $functions = get_extension_funcs('oxphp_sapi'); print_r($functions); // Array // ( // [0] => oxphp_http_request // [1] => oxphp_superglobals_enabled // [2] => oxphp_request_id // [3] => oxphp_worker_id // [4] => oxphp_server_info // [5] => oxphp_finish_request // [6] => oxphp_is_worker // [7] => oxphp_is_streaming // [8] => oxphp_stream_flush // [9] => oxphp_sleep // [10] => oxphp_usleep // [11] => oxphp_worker // [12] => oxphp_register_decorator // [13] => oxphp_async // [14] => oxphp_async_await // [15] => oxphp_async_await_all // [16] => oxphp_async_await_race // [17] => oxphp_async_await_any // [18] => oxphp_apm_trace // [19] => oxphp_apm_start // [20] => oxphp_apm_end // [21] => oxphp_apm_attribute // [22] => oxphp_apm_event // [23] => oxphp_apm_error // [24] => oxphp_apm_status // [25] => oxphp_apm_trace_id // [26] => oxphp_apm_span_id // [27] => oxphp_apm_header // )
Note

Основные функции SAPI (вплоть до oxphp_register_decorator) идут первыми; семейства oxphp_async_* и oxphp_apm_* — а также SDK OxPHP\Profile\*, когда профилировщик встроен, — добавляются их плагинами во время инициализации модуля. Считайте этот список иллюстративным: точный набор и порядок зависят от того, какие плагины скомпилированы в сборку.

Совместимость с PHP-FPM

Если ваш код должен работать и на OxPHP, и на PHP-FPM, используйте обёртки-запасные варианты:

php
<?php function finish_request(): bool { if (function_exists('oxphp_finish_request')) { return oxphp_finish_request(); } if (function_exists('fastcgi_finish_request')) { return fastcgi_finish_request(); } return false; } // Worker-aware bootstrap if (function_exists('oxphp_is_worker') && oxphp_is_worker()) { // OxPHP worker mode } else { // PHP-FPM or OxPHP traditional mode }
Note

Семейство функций oxphp_async() всегда зарегистрировано в OxPHP, поэтому function_exists('oxphp_async') возвращает true, даже когда ASYNC_WORKERS=0. Когда пул отключён, вызов любой асинхронной функции выбрасывает OxPHP\Async\AsyncException. Если ваш код должен обрабатывать обе конфигурации, перехватывайте исключение, а не проверяйте function_exists().

См. также

Нашли ошибку? Сообщите →