PHP-функції
OxPHP реєструє свої функції через розширення oxphp_sapi, яке автоматично завантажується для кожного PHP-скрипту, що його виконує сервер. Ні директива extension=, ні ручне завантаження не потрібні. Кожна з наведених тут функцій доступна з першого рядка вашого PHP-коду.
Зміст
- oxphp_http_request()
- oxphp_superglobals_enabled()
- oxphp_request_id()
- oxphp_worker_id()
- oxphp_server_info()
- oxphp_finish_request()
- oxphp_is_worker()
- oxphp_worker()
- oxphp_is_streaming()
- oxphp_stream_flush()
- oxphp_sleep()
- oxphp_usleep()
- oxphp_async()
- oxphp_async_await()
- oxphp_async_await_all()
- oxphp_async_await_race()
- oxphp_async_await_any()
- oxphp_register_decorator()
- oxphp_apm_trace()
- oxphp_apm_start()
- oxphp_apm_end()
- oxphp_apm_attribute()
- oxphp_apm_event()
- oxphp_apm_error()
- oxphp_apm_status()
- oxphp_apm_trace_id()
- oxphp_apm_span_id()
- oxphp_apm_header()
- OxPHP\Profile\is_active()
- OxPHP\Profile\start()
- OxPHP\Profile\stop()
- OxPHP\Profile\pause()
- OxPHP\Profile\resume()
- OxPHP\Profile\mark()
- OxPHP\Profile\metric()
- Класи та інтерфейси
- Винятки
oxphp_http_request()
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
$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()
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
if (oxphp_superglobals_enabled()) {
$query = $_GET['page'] ?? 1;
} else {
$query = oxphp_http_request()->query('page', 1);
}oxphp_request_id()
oxphp_request_id(): stringПовертає унікальний ідентифікатор поточного запиту. Це те саме значення, що надсилається в заголовку відповіді X-Request-ID. Якщо клієнт надсилає заголовок X-Request-ID, OxPHP передає його без змін замість того, щоб генерувати новий.
Повертає: 20-символьний шістнадцятковий рядок, коли ідентифікатор генерує OxPHP (наприклад, "67890abc12341a2b0042"). Коли клієнт надсилає заголовок X-Request-ID, повертається саме це значення (1–64 символи: латинські літери, цифри, а також -, _, .).
Приклад:
<?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()
oxphp_worker_id(): intПовертає індекс (з відліком від нуля) потоку PHP-воркера, що обробляє поточний запит. Індекси воркерів лежать у діапазоні від 0 до PHP_WORKERS - 1.
Повертає: ціле число, що ідентифікує поточний потік воркера.
Приклад:
<?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()
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
$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()
oxphp_finish_request(): boolНадсилає відповідь клієнту й продовжує виконання PHP у фоні. Клієнт одразу отримує повну HTTP-відповідь, а скрипт працює далі, доки не завершиться природним шляхом. Це відповідник fastcgi_finish_request() з PHP-FPM в OxPHP.
Повертає: true у разі успіху, false, якщо для цього запиту функцію вже викликали.
Потік 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()
oxphp_is_worker(): boolПовертає, чи працює сервер у режимі воркерів. Режим воркерів вмикається за WORKER_MODE_ENABLED=true.
Повертає: true у режимі воркерів, false у традиційному режимі.
Приклад:
<?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()
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() виконується за кожного з цих виходів, а не лише за першого. На динамічному пулі це стає регулярною подією на цілком справному сервері: простійний воркер виводиться з роботи, виконується його завершальний код, а решта пулу продовжує обслуговувати запити. Пишіть цей блок як завершення роботи воркера, а не зупинку сервера. Рядок, який там записує в лог «сервер зупиняється», хибний за кожного виходу, крім останнього, а ресурс, спільний не лише для цього воркера, буде знищено, поки сервер ще працює.
oxphp_worker() працює лише в режимі воркерів (WORKER_MODE_ENABLED=true). У традиційному режимі функція записує попередження в лог і повертає false.
Приклад:
<?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()
oxphp_is_streaming(): boolПовертає, чи перебуває поточний запит у потоковому режимі. Потоковий режим вмикається під час першого виклику oxphp_stream_flush() або автоматично, коли PHP встановлює Content-Type: text/event-stream.
Повертає: true, якщо потоковий режим активний, інакше false.
Приклад:
<?php
if (oxphp_is_streaming()) {
echo "data: " . json_encode($event) . "\n\n";
oxphp_stream_flush();
} else {
echo json_encode($allData);
}oxphp_stream_flush()
oxphp_stream_flush(): boolВмикає потоковий режим і надсилає клієнту весь буферизований вивід як HTTP-чанк. Під час першого виклику HTTP-заголовки надсилаються одразу й починається потокова передача. Кожен наступний виклик надсилає вивід, записаний після попереднього.
Повертає: true у разі успіху, false, якщо oxphp_finish_request() уже було викликано.
Потоковий режим також вмикається автоматично, коли PHP встановлює Content-Type: text/event-stream. У такому разі можна використовувати вбудовану в PHP функцію flush(), але спершу викличте ob_end_flush(), щоб обійти шар буферизації виводу 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()
oxphp_sleep(float $seconds): voidЗасинає на вказаний час. Усередині обробника режиму воркерів, що виконується у файбері, цей виклик кооперативний: він призупиняє поточний файбер, щоб під час очікування могли оброблятися інші запити. Поза файбером функція вдається до звичайного блокувального usleep().
Вона також блокує там, де перемикання файбера заборонене, тобто всюди, де вихід із поточного фрейму був би небезпечним:
- усередині обробника
declare(ticks) - усередині диспетчеризації сигналів pcntl
- поки формуються вхідні дані запиту
- усередині
FILTER_CALLBACK, до якого дійшли зfilter_input_array()з масивом визначень - усередині завершальних обходів, що викликають деструктори після того, як запит розвалився
Вона також блокує, якщо її викликано у файбері, запущеному планувальником рівня користувача (AMPHP, Revolt, звичайний new Fiber), бо планувальник OxPHP не може відновити такий контекст. Хуки середовища виконання описують ту саму межу для перехоплених нативних вбудованих функцій.
oxphp_sleep() працює кооперативно в режимі воркерів без жодних налаштувань і приймає дробові значення секунд. RUNTIME_HOOKS=sleep — окреме доопрацювання, що вмикається за бажанням: воно робить кооперативними й нативні виклики sleep()/usleep() (наприклад, у сторонньому коді) в тих самих межах. Воно не скасовує потреби в oxphp_sleep() у коді, який ви контролюєте. Дивіться Хуки середовища виконання.
Параметри:
$seconds— тривалість сну в секундах. Приймаються дробові значення (наприклад,0.5для 500 мілісекунд). За значень0або менших функція повертається одразу.
Повертає: void
Приклад:
<?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()
oxphp_usleep(int $microseconds): voidЗасинає на вказану кількість мікросекунд. Як і oxphp_sleep(), усередині файбера цей виклик кооперативний, а в інших випадках вдається до блокувального usleep(), зокрема в контекстах, перелічених у розділі oxphp_sleep(), де перемикання файбера заборонене або OxPHP не володіє контекстом.
Параметри:
$microseconds— тривалість сну в мікросекундах. За значень0або менших функція повертається одразу.
Повертає: void
Приклад:
<?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()
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-змінні містять об’єкти чи ресурси
Змінні, захоплені замиканням через use, підпадають під ті самі обмеження: об’єкти й ресурси відхиляються.
Приклад:
<?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()
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
$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()
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
$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()
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
// 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()
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
$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()
oxphp_register_decorator(string $class): boolРеєструє PHP-клас як декоратор, що обгортає виклики функцій і методів. Клас має реалізовувати OxPHP\Decorator\AttributeInterface. Після реєстрації OxPHP викликає хуки декоратора before() і after() навколо кожного виклику функції чи методу, що відповідає цілям #[Attribute] декоратора.
Параметри:
$class— повне ім’я класу декоратора, який треба зареєструвати
Повертає: true у разі успіху, false, якщо клас не існує або не реалізує OxPHP\Decorator\AttributeInterface.
Приклад:
<?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()
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
$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()
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
$spanId = oxphp_apm_start('order.validate', [
'order.type' => 'subscription',
]);
validateOrder($order);
oxphp_apm_end($spanId);oxphp_apm_end()
oxphp_apm_end(int $span_id): voidЗакриває спан, відкритий через oxphp_apm_start(). Час завершення спану записується, і спан переходить з активного стека до списку завершених, готових до експорту.
Параметри:
$span_id— локальний ідентифікатор спану, поверненийoxphp_apm_start()
Повертає: void
Завжди закривайте спани у зворотному порядку. Якщо ви відкрили спан A, а потім спан B, закрийте B раніше за A. Незакриті спани автоматично закриваються наприкінці запиту й позначаються oxphp.span.leaked=true.
oxphp_apm_attribute()
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
$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()
oxphp_apm_event(string $name, ?array $attributes = null, ?int $span_id = null): voidЗаписує подію з міткою часу на спані. Події зручні для фіксації окремих випадків упродовж життя спану (наприклад, промах кешу, повторна спроба, перевірка авторизації).
Параметри:
$name— назва події (наприклад,"cache.miss","retry")$attributes— необов’язковий асоціативний масив рядкових атрибутів події «ключ — значення»$span_id— необов’язковий локальний ідентифікатор спану. Якщо його не вказано, використовується поточний спан
Повертає: void
Приклад:
<?php
$spanId = oxphp_apm_start('payment.process');
oxphp_apm_event('payment.authorized', [
'provider' => 'stripe',
'amount' => '49.99',
]);
oxphp_apm_end($spanId);oxphp_apm_error()
oxphp_apm_error(mixed $exception, ?int $span_id = null): voidВстановлює статус спану як помилковий (код статусу 2). Використовуйте цю функцію, щоб позначати спани, у яких виник виняток або збій.
Параметри:
$exception— виняток або помилка (використовується для контексту; статус встановлюється незалежно від типу)$span_id— необов’язковий локальний ідентифікатор спану. Якщо його не вказано, використовується поточний спан
Повертає: void
Приклад:
<?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()
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
$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()
oxphp_apm_trace_id(): stringПовертає ідентифікатор трасування W3C (32 шістнадцяткові символи) для контексту трасування поточного запиту. Це те саме значення, що й $_SERVER['OXPHP_TRACE_ID'], доступне без суперглобальних змінних.
Повертає: 32-символьний шістнадцятковий рядок з ідентифікатором трасування. Коли APM вимкнено або контекст трасування не активний, повертає порожній рядок.
Приклад:
<?php
$traceId = oxphp_apm_trace_id();
error_log("Processing request in trace {$traceId}");oxphp_apm_span_id()
oxphp_apm_span_id(): stringПовертає ідентифікатор (16 шістнадцяткових символів) поточного активного спану. Якщо спани вкладені, повертає ідентифікатор найглибшого відкритого спану.
Повертає: 16-символьний шістнадцятковий рядок з ідентифікатором спану. Коли активного спану немає, повертає порожній рядок.
oxphp_apm_header()
oxphp_apm_header(): stringПовертає значення заголовка W3C traceparent для контексту поточного спану. Використовуйте його, щоб передавати контекст трасування в подальші HTTP-виклики.
Повертає: рядок у форматі 00-{trace_id}-{span_id}-01. Коли контекст трасування не активний, повертає порожній рядок.
Приклад:
<?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()
OxPHP\Profile\is_active(): boolПовертає true, коли для цього запиту зараз активне захоплення профілю, тобто його ввімкнув тригер (заголовок, cookie, параметр рядка запиту або частота вибірки) або скрипт викликав start(), і захоплення не призупинено через pause() чи stop(). Коли профайлер вимкнено (PROFILER_ENABLED), тригери не перевіряються, а start() нічого не робить, тож жодне з них захоплення не вмикає.
Корисно для захисту дорогого інструментування, яке має працювати лише тоді, коли профілювання ввімкнене.
Повертає: bool.
Приклад:
<?php
if (OxPHP\Profile\is_active()) {
OxPHP\Profile\mark('checkpoint.before_query');
}OxPHP\Profile\start()
OxPHP\Profile\start(): voidПрограмно вмикає захоплення профілю до кінця поточного запиту, навіть якщо на етапі RINIT жоден тригер не спрацював. Встановлює режим профілювання PROFILE_ALL і скидає прапорець паузи.
Нічого не робить, поки профайлер вимкнено (PROFILER_ENABLED): тоді профайлер не записує жодних викликів функцій, тож виклик не вмикає захоплення й не змушує is_active() повертати true.
Якщо профіль уже був активний в іншому режимі, цей виклик підвищує його: спани, зібрані в нижчому режимі, відкидаються, щоб захоплений профіль був внутрішньо узгодженим. Використовуйте цю функцію, коли хочете ввімкнути профілювання для конкретної гілки коду, не покладаючись на тригери.
Повертає: void.
Приклад:
<?php
if ($request->header('x-debug') === 'on') {
OxPHP\Profile\start();
}OxPHP\Profile\stop()
OxPHP\Profile\stop(): voidВимикає подальше захоплення спанів для цього запиту. Відкриті на цю мить спани закриваються природним шляхом, коли PHP виходить із них, тож стек викликів лишається збалансованим — перестають записуватися лише нові спани.
Повертає: void.
Приклад:
<?php
OxPHP\Profile\start();
expensive_work();
OxPHP\Profile\stop();
non_profiled_work();OxPHP\Profile\pause()
OxPHP\Profile\pause(): voidМ’який варіант stop(). Ефект той самий (встановлює прапорець паузи); різниця в намірі: pause() сигналізує, що захоплення згодом відновиться через resume(), а stop() — ні.
Повертає: void.
OxPHP\Profile\resume()
OxPHP\Profile\resume(): voidСкидає прапорець паузи, встановлений pause() або stop(). Сам режим профілювання не змінюється: якщо його ніколи не вмикали, resume() не робить нічого помітного.
Повертає: void.
Приклад:
<?php
OxPHP\Profile\pause();
$secret = decrypt_payload($data);
OxPHP\Profile\resume();OxPHP\Profile\mark()
OxPHP\Profile\mark(string $label, ?array $attrs = null): voidДодає подію Mark до найвищого відкритого спану з необов’язковим набором атрибутів. Нічого не робить, якщо відкритого спану немає (наприклад, профілювання не активне або mark() викликано на верхньому рівні запиту поза будь-яким інструментованим фреймом).
Ключі та значення атрибутів приводяться до рядків; нерядкові значення стають порожнім рядком.
Параметри:
$label— коротка зрозуміла людині назва події (наприклад,"cache.miss","db.slow_query")$attrs— необов’язковийarray<string, scalar>пар «ключ — значення», що додаються до події
Повертає: void.
Приклад:
<?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()
OxPHP\Profile\metric(string $name, float $value): voidДодає атрибут metric.<name> до поточного відкритого спану. Нічого не робить, якщо відкритого спану немає.
На відміну від mark() (яка створює окрему подію), metric() записує значення в набір атрибутів наявного спану — це зручно для фіксації числових спостережень, пов’язаних із навколишньою операцією (кількість отриманих рядків, оброблених байтів, повторних спроб).
Параметри:
$name— ідентифікатор метрики; зберігається якmetric.<name>$value— числове значення (приводиться доfloat)
Повертає: void.
Приклад:
<?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
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
// )Основні функції SAPI (до oxphp_register_decorator включно) ідуть першими; родини oxphp_async_* і oxphp_apm_*, а також SDK OxPHP\Profile\*, коли профайлер вбудовано, додаються їхніми плагінами під час ініціалізації модуля. Сприймайте цей список як ілюстрацію: точний набір і порядок залежать від того, які плагіни скомпільовано в збірку.
Сумісність із PHP-FPM
Якщо ваш код має працювати і на OxPHP, і на PHP-FPM, використовуйте обгортки із запасним варіантом:
<?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
}Родина функцій oxphp_async() в OxPHP зареєстрована завжди, тож function_exists('oxphp_async') повертає true навіть за ASYNC_WORKERS=0. Коли пул вимкнено, виклик будь-якої асинхронної функції викидає OxPHP\Async\AsyncException. Якщо ваш код має працювати за обох конфігурацій, перехоплюйте виняток, а не перевіряйте function_exists().
Див. також
- HTTP Request API — об’єктно-орієнтований доступ до даних запиту через
oxphp_http_request() - Режим воркерів — постійний цикл воркера та життєвий цикл запиту
- Server-Sent Events — потокова передача в реальному часі за допомогою
oxphp_stream_flush() - Рання відповідь — фонова обробка за допомогою
oxphp_finish_request() - Суперглобальні змінні — як OxPHP заповнює
$_SERVER,$_GET,$_POSTта інші суперглобальні змінні - Розподілене трасування та APM — W3C Trace Context, експорт OTel і SDK
oxphp_apm_*() - Довідник конфігурації —
WORKER_MODE_ENABLED,ENTRY_FILE,PHP_WORKERSта інші змінні середовища