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() виконується за кожного з цих виходів, а не лише за першого. На динамічному пулі це стає регулярною подією на цілком справному сервері: простійний воркер виводиться з роботи, виконується його завершальний код, а решта пулу продовжує обслуговувати запити. Пишіть цей блок як завершення роботи воркера, а не зупинку сервера. Рядок, який там записує в лог «сервер зупиняється», хибний за кожного виходу, крім останнього, а ресурс, спільний не лише для цього воркера, буде знищено, поки сервер ще працює.

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(). Це аналог Promise.race з JavaScript.

Параметри:

  • $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

Повертається, щойно будь-який проміс ВИКОНАНО. Відхилення накопичуються й стають видимими, лише якщо відхилено всі проміси. Це аналог Promise.any з JavaScript — зручний для сценаріїв із резервуванням, коли вам підходить будь-яке джерело, що спрацює.

Параметри:

  • $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() (ключі — ідентифікатори) та 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() не потрібен.

Колбек отримує локальний ідентифікатор спану як єдиний аргумент. Передайте його в 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 без урахування регістру), колбек однаково виконується, а його значення однаково повертається. Як ідентифікатор спану він отримує 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. Коли APM вимкнено, повертає 0.

Приклад:

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 (32 шістнадцяткові символи) для контексту трасування поточного запиту. Це те саме значення, що й $_SERVER['OXPHP_TRACE_ID'], доступне без суперглобальних змінних.

Повертає: 32-символьний шістнадцятковий рядок з ідентифікатором трасування. Коли 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

Повертає ідентифікатор (16 шістнадцяткових символів) поточного активного спану. Якщо спани вкладені, повертає ідентифікатор найглибшого відкритого спану.

Повертає: 16-символьний шістнадцятковий рядок з ідентифікатором спану. Коли активного спану немає, повертає порожній рядок.

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> (ключі — ідентифікатори промісів), getPromiseIds(): list<int> (вхідні ідентифікатори промісів за порядком).
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().

Див. також