PHP Functions
OxPHP registers its functions through the oxphp_sapi extension, which loads automatically for every PHP script the server executes. No extension= directive and no manual loading are required. Every function listed here is available from the first line of your PHP code.
Table of Contents
- 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()
- Classes and Interfaces
- Exceptions
oxphp_http_request()
oxphp_http_request(): \OxPHP\Http\RequestReturns the request object for the current HTTP request. The object provides typed access to the HTTP method, URI, query parameters, parsed body, headers, cookies, uploaded files, client IP, and request timing.
Returns: An \OxPHP\Http\Request instance backed by the request data in the current PHP worker thread.
Throws: An exception from the OxPHP\Http\Exception namespace when called outside an active request:
| Exception | Situation |
|---|---|
\OxPHP\Http\Exception\WorkerIdleException |
Worker mode, between requests |
\OxPHP\Http\Exception\AsyncContextException |
Inside an oxphp_async() callback |
\OxPHP\Http\Exception\NoActiveRequestException |
Any other context without an active request |
In normal request-handling code, no exception handling is required.
Example:
<?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');For the complete interface reference, see the HTTP Request API documentation.
oxphp_superglobals_enabled()
oxphp_superglobals_enabled(): boolReturns whether superglobal population is enabled for this server instance. The value reflects the SUPERGLOBALS_ENABLED environment variable and does not change during the server's lifetime.
When false, $_GET, $_POST, $_COOKIE, $_FILES, and $_SERVER are empty arrays. The HTTP Object API (oxphp_http_request()), php://input, and PHP session functions are unaffected.
Returns: true when SUPERGLOBALS_ENABLED is true (the default), false otherwise.
Example:
<?php
if (oxphp_superglobals_enabled()) {
$query = $_GET['page'] ?? 1;
} else {
$query = oxphp_http_request()->query('page', 1);
}oxphp_request_id()
oxphp_request_id(): stringReturns the unique request identifier for the current request. This is the same value sent in the X-Request-ID response header. If the client sends an X-Request-ID header, OxPHP passes it through unchanged instead of generating a new one.
Returns: A 20-character hexadecimal string when OxPHP generates the ID (e.g. "67890abc12341a2b0042"). When the client sends an X-Request-ID header, that value is returned as-is (1–64 characters, alphanumeric plus -, _, .).
Example:
<?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(): intReturns the zero-based index of the PHP worker thread handling the current request. Worker indices range from 0 to PHP_WORKERS - 1.
Returns: An integer identifying the current worker thread.
Example:
<?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(): arrayReturns an associative array with server and request metadata.
Returns: An array with the following keys:
| Key | Type | Description |
|---|---|---|
version |
string |
Server version (e.g. "0.10.0") |
worker_id |
int |
Same value as oxphp_worker_id() |
request_time |
float |
Unix timestamp with microsecond precision when the request started |
worker_mode |
bool |
Whether the current process runs in worker mode |
Example:
<?php
$info = oxphp_server_info();
// [
// "version" => "0.10.0",
// "worker_id" => 3,
// "request_time" => 1738800000.123456,
// "worker_mode" => true,
// ]
$elapsed = microtime(true) - $info['request_time'];
echo "Processing took {$elapsed}s so far";oxphp_finish_request()
oxphp_finish_request(): boolFlushes the response to the client and continues PHP execution in the background. The client receives the complete HTTP response immediately; the script keeps running until it exits naturally. This is the OxPHP equivalent of fastcgi_finish_request() in PHP-FPM.
Returns: true on success, false if already called on this request.
The PHP worker thread remains occupied until the script finishes. Keep background work short or offload heavy processing to a queue.
Example:
<?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(): boolReturns whether the server is running in worker mode. Worker mode activates when WORKER_MODE_ENABLED=true.
Returns: true if running in worker mode, false in traditional mode.
Example:
<?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): boolEnters the persistent worker mode loop. OxPHP calls $handler once for each incoming HTTP request. Between requests, a soft reset clears per-request state — output buffers, headers, and superglobals — without destroying the PHP heap, so any variables declared outside the handler persist across requests.
Parameters:
$handler— Called once per request. The handler receives no arguments. Use superglobals ($_SERVER,$_GET,$_POST, etc.) oroxphp_http_request()inside the handler to access request data.
Returns: true on graceful shutdown, false if not in worker mode.
The worker loop exits when any of the following conditions are met:
- The server shuts down gracefully
- The handler raises 3 consecutive uncaught exceptions or fatal errors
- The worker exceeds
WORKER_MAX_MEMORY_MIB - The application calls
Worker::scheduleExit()
oxphp_worker() only works in worker mode (WORKER_MODE_ENABLED=true). In traditional mode it logs a warning and returns false.
Example:
<?php
// worker.php — runs once per worker process 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();
});
// Code after oxphp_worker() runs during shutdown
$app->terminate();oxphp_is_streaming()
oxphp_is_streaming(): boolReturns whether the current request is in streaming mode. Streaming mode activates on the first call to oxphp_stream_flush() or automatically when PHP sets Content-Type: text/event-stream.
Returns: true if streaming mode is active, false otherwise.
Example:
<?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(): boolActivates streaming mode and flushes any buffered output to the client as an HTTP chunk. On the first call, HTTP headers are sent immediately and streaming begins. Each subsequent call flushes output written since the last flush.
Returns: true on success, false if oxphp_finish_request() was already called.
Streaming mode also activates automatically when PHP sets Content-Type: text/event-stream. In that case you can use PHP's built-in flush(), but call ob_end_flush() first to bypass PHP's output buffering layer.
Example:
<?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 — does not block the worker in fiber mode
}oxphp_sleep()
oxphp_sleep(float $seconds): voidSleeps for the specified duration. Inside a worker mode handler running in a fiber, this call is cooperative — it suspends the current fiber so other requests can be processed during the wait. Outside a fiber, it falls back to a standard blocking usleep().
Parameters:
$seconds— Duration to sleep in seconds. Fractional values are accepted (e.g.0.5for 500 milliseconds). Values of0or less return immediately.
Returns: void
Example:
<?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): voidSleeps for the specified number of microseconds. Like oxphp_sleep(), this is cooperative inside a fiber and falls back to blocking usleep() otherwise.
Parameters:
$microseconds— Duration to sleep in microseconds. Values of0or less return immediately.
Returns: void
Example:
<?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): intDispatches a closure for execution on a dedicated async worker thread and returns a promise ID immediately. The caller continues executing without waiting for the closure to finish. Use oxphp_async_await() to retrieve the result.
Parameters:
$closure— A user-definedClosureto run on an async worker thread...$args— Arguments to pass to the closure. Scalar values (null,bool,int,float,string), arrays of those, andOxPHP\Shared\*instances (the only objects that may cross the thread boundary) are accepted. Resources and any non-Sharedobject are rejected.
Returns: An integer promise ID. Pass this to oxphp_async_await(), oxphp_async_await_all(), oxphp_async_await_race(), or oxphp_async_await_any().
Throws: OxPHP\Async\AsyncException in the following cases:
- The async pool is disabled (
ASYNC_WORKERS=0) — message: "Async pool is disabled. Set ASYNC_WORKERS > 0 to enable." - The closure is not user-defined
- The async pool is full (all queue slots occupied)
- Arguments or
use-variables contain objects or resources
Use-vars captured via use in the closure follow the same restrictions — objects and resources are rejected.
Example:
<?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): mixedBlocks until the specified async promise completes and returns its result. Inside a worker mode fiber, this suspends the current fiber cooperatively rather than blocking the thread.
Parameters:
$promise_id— A promise ID returned byoxphp_async()$timeout— Maximum seconds to wait.0.0means wait indefinitely. Default:0.0
Returns: The return value of the async closure.
Throws:
OxPHP\Async\AsyncExceptionif the async pool is disabled (ASYNC_WORKERS=0), or if the async task threw an exceptionOxPHP\Async\TimeoutExceptionif$timeoutis exceeded
Example:
<?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): arrayAwaits all promises in the array and returns an associative array mapping each promise ID to its result. Promises are awaited in array order.
Parameters:
$promise_ids— An array of integer promise IDs returned byoxphp_async()$timeout— Maximum seconds to wait per promise.0.0means wait indefinitely. Default:0.0
Returns: An associative array where each key is a promise ID (integer) and each value is the result of that promise.
Throws:
OxPHP\Async\AsyncExceptionif the async pool is disabled (ASYNC_WORKERS=0), or if any promise failsOxPHP\Async\TimeoutExceptionif any promise exceeds$timeout
Example:
<?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): arrayRaces multiple promises and returns the first one to settle, whether it fulfilled or rejected. The other promises are not cancelled — they continue running and remain awaitable with oxphp_async_await(). This is the JavaScript Promise.race analog.
Parameters:
$promise_ids— An array of at least one integer promise ID returned byoxphp_async(). Must not be empty.$timeout— Maximum seconds to wait for any promise to settle.0.0means wait indefinitely. Default:0.0
Returns: An associative array with two keys:
id(int) — The promise ID of the winnervalue(mixed) — The return value of the winning promise
Throws:
OxPHP\Async\AsyncExceptionif the async pool is disabled (ASYNC_WORKERS=0), or if the winning promise rejectedOxPHP\Async\TimeoutExceptionif no promise settles within$timeout
Example:
<?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): arrayReturns as soon as one promise FULFILLS. Rejections are accumulated, and only become observable if every promise rejects. This is the JavaScript Promise.any analog — useful for fallback / redundancy patterns where you want any source that works.
Parameters:
$promise_ids— An array of at least one integer promise ID returned byoxphp_async(). Must not be empty.$timeout— Maximum seconds to wait for the first fulfillment.0.0means wait indefinitely. Default:0.0
Returns: An associative array with two keys:
id(int) — The promise ID of the first fulfilled promisevalue(mixed) — The return value of the winning promise
Throws:
OxPHP\Async\AsyncExceptionif the async pool is disabled (ASYNC_WORKERS=0)OxPHP\Async\AggregateAsyncExceptionif every promise rejected. The exception carries every error viagetErrors()(positional, keyed 0..N-1),getErrorMap()(id-keyed), andgetPromiseIds().OxPHP\Async\TimeoutExceptionif no promise fulfilled within$timeout.getPartialErrors()lists the promises that already rejected before the deadline;getCancelledPromiseIds()lists those that had not settled and have therefore been cancelled. Their cancel flag is set and their receivers are dropped — passing any of these ids tooxphp_async_await*()afterwards throws"unknown or already-awaited promise id". The list is an audit trail, not a queue of resumable work.
Behavior:
- Promises that were still pending at the moment of victory remain awaitable individually with
oxphp_async_await(). - Promises that already rejected before the winner do not — their results were consumed when accumulated as candidate errors.
Example:
<?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): boolRegisters a PHP class as a decorator that wraps function and method calls. The class must implement OxPHP\Decorator\AttributeInterface. Once registered, OxPHP invokes the decorator's before() and after() hooks around every function or method call that matches the decorator's #[Attribute] targets.
Parameters:
$class— The fully qualified class name of the decorator to register
Returns: true on success, false if the class does not exist or does not implement OxPHP\Decorator\AttributeInterface.
Example:
<?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): voidExecutes a callback inside a named span. The span is opened before the callback runs and closed after it returns. Reserved for future enhanced callback integration.
Parameters:
$name— Span name$callback— Callable to execute inside the span$attributes— Optional associative array of string key-value attributes
Returns: void
oxphp_apm_start()
oxphp_apm_start(string $name, ?array $attributes = null): intOpens a new span and returns a local ID for later reference. The span becomes a child of the currently active span (or the request root span if no span is active). Use oxphp_apm_end() to close it.
Parameters:
$name— Span name (e.g."cache.warm","payment.process")$attributes— Optional associative array of string key-value attributes to set on the span at creation
Returns: An integer local span ID. Pass this to oxphp_apm_end(), oxphp_apm_attribute(), or other functions that accept a $span_id. Returns 0 when APM is disabled.
Example:
<?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): voidCloses the span opened by oxphp_apm_start(). The span's end time is recorded and it moves from the active stack to the finished list, ready for export.
Parameters:
$span_id— The local span ID returned byoxphp_apm_start()
Returns: void
Always close spans in reverse order. If you open span A then span B, close B before A. Unclosed spans are automatically closed at request end and marked with oxphp.span.leaked=true.
oxphp_apm_attribute()
oxphp_apm_attribute(string $key, mixed $value, ?int $span_id = null): voidSets a key-value attribute on a span. Values are converted to strings. If no $span_id is provided, the attribute is added to the currently active span.
Parameters:
$key— Attribute key (e.g."user.id","cache.hit")$value— Attribute value (string, int, float, bool, or null -- converted to string)$span_id— Optional local span ID. When omitted, targets the current span
Returns: void
Example:
<?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): voidRecords a timestamped event on a span. Events are useful for logging discrete occurrences within a span's lifetime (e.g. cache miss, retry attempt, authorization check).
Parameters:
$name— Event name (e.g."cache.miss","retry")$attributes— Optional associative array of string key-value event attributes$span_id— Optional local span ID. When omitted, targets the current span
Returns: void
Example:
<?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): voidMarks a span's status as error (status code 2). Use this to flag spans where an exception or failure occurred.
Parameters:
$exception— The exception or error (used for context; status is set regardless of type)$span_id— Optional local span ID. When omitted, targets the current span
Returns: void
Example:
<?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): voidSets the status code and optional description on a span.
Parameters:
$code— Status code:0= Unset,1= Ok,2= Error$description— Optional human-readable status description$span_id— Optional local span ID. When omitted, targets the current span
Returns: void
Example:
<?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(): stringReturns the W3C trace ID (32 hex characters) for the current request's trace context. This is the same value as $_SERVER['OXPHP_TRACE_ID'], available without superglobals.
Returns: A 32-character hexadecimal trace ID string. Returns an empty string when APM is disabled or no trace context is active.
Example:
<?php
$traceId = oxphp_apm_trace_id();
error_log("Processing request in trace {$traceId}");oxphp_apm_span_id()
oxphp_apm_span_id(): stringReturns the span ID (16 hex characters) of the currently active span. If there are nested spans, this returns the innermost open span's ID.
Returns: A 16-character hexadecimal span ID string. Returns an empty string when no span is active.
oxphp_apm_header()
oxphp_apm_header(): stringReturns a W3C traceparent header value for the current span context. Use this to propagate trace context to downstream HTTP calls.
Returns: A string in the format 00-{trace_id}-{span_id}-01. Returns an empty string when no trace context is active.
Example:
<?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(): boolReturns true when profile capture is currently active for this request — i.e. the profiler has been triggered (by header, cookie, query parameter, or sample rate) and capture has not been paused via pause().
Useful for guarding expensive instrumentation that should only run when profiling is on.
Returns: bool.
Example:
<?php
if (OxPHP\Profile\is_active()) {
OxPHP\Profile\mark('checkpoint.before_query');
}OxPHP\Profile\start()
OxPHP\Profile\start(): voidProgrammatically enables profile capture for the remainder of the current request, even if no trigger fired at RINIT. Sets profiling mode to PROFILE_ALL and clears the paused flag.
If a profile was already active in a different mode, this call promotes it — any spans already collected in the lower mode are discarded so the captured profile is internally consistent. Use this when you want to opt a specific code path into profiling without relying on triggers.
Returns: void.
Example:
<?php
if ($request->header('x-debug') === 'on') {
OxPHP\Profile\start();
}OxPHP\Profile\stop()
OxPHP\Profile\stop(): voidDisables further span capture for this request. Currently-open spans close naturally as PHP returns from them, so the call stack remains balanced — only new spans stop being recorded.
Returns: void.
Example:
<?php
OxPHP\Profile\start();
expensive_work();
OxPHP\Profile\stop();
non_profiled_work();OxPHP\Profile\pause()
OxPHP\Profile\pause(): voidSoft variant of stop(). Same effect (sets the paused flag); the distinction is intent — pause() signals that capture will resume later via resume(), while stop() does not.
Returns: void.
OxPHP\Profile\resume()
OxPHP\Profile\resume(): voidClears the paused flag set by pause() or stop(). Profile mode itself is not changed — if it was never enabled, resume() does nothing observable.
Returns: void.
Example:
<?php
OxPHP\Profile\pause();
$secret = decrypt_payload($data);
OxPHP\Profile\resume();OxPHP\Profile\mark()
OxPHP\Profile\mark(string $label, ?array $attrs = null): voidAttaches a Mark event to the topmost open span, with an optional attribute bag. No-op when no span is open (e.g. profiling not active, or mark() called at request top-level outside any instrumented frame).
Attribute keys and values are coerced to strings; non-string values become an empty string.
Parameters:
$label— short human-readable name for the event (e.g."cache.miss","db.slow_query")$attrs— optionalarray<string, scalar>of key/value pairs attached to the event
Returns: void.
Example:
<?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): voidAppends a metric.<name> attribute to the current open span. No-op when no span is open.
Unlike mark() (which creates a discrete event), metric() writes onto the existing span's attribute set — useful for recording numeric observations tied to the surrounding operation (rows fetched, bytes processed, retry count).
Parameters:
$name— metric identifier; will be stored asmetric.<name>$value— numeric value (coerced tofloat)
Returns: void.
Example:
<?php
function search(string $query): array {
$results = $index->search($query);
OxPHP\Profile\metric('result_count', count($results));
return $results;
}Classes and Interfaces
The oxphp_sapi extension registers the following classes:
HTTP
| Class | Description |
|---|---|
OxPHP\Http\Request |
Request object returned by oxphp_http_request(). final — cannot be extended. |
OxPHP\Http\Attributes |
Mutable request attributes container (for middleware). final. |
OxPHP\Http\Session |
Session object accessible via $request->session(). final. |
OxPHP\Http\UploadedFile |
Uploaded file object from $request->files(). final. |
Decorators
| Class / Interface | Description |
|---|---|
OxPHP\Decorator\AttributeInterface |
Interface for decorators. Requires before(Context $ctx) and after(Context $ctx) methods. |
OxPHP\Decorator\Context |
Context object passed to decorator hooks. final. Public properties: target, class, method, function, objectId, requestId, traceId. Methods: getParams(): array, getResult(): mixed, hasResult(): bool. See Decorators for the full reference. |
Tracing
| Class | Description |
|---|---|
OxPHP\Apm\Trace |
Built-in attribute for automatic span creation. Apply to functions or methods. |
Async
| Class | Description |
|---|---|
OxPHP\Async\BorrowedProxy |
Proxy object for borrowed values between threads. |
Exceptions
All exceptions registered by the extension:
| Exception | Extends | When thrown |
|---|---|---|
OxPHP\Async\AsyncException |
\Exception |
Error in an async task (oxphp_async_await()) or invalid arguments in oxphp_async() |
OxPHP\Async\TimeoutException |
OxPHP\Async\AsyncException |
Timeout exceeded in any of oxphp_async_await(), oxphp_async_await_all(), oxphp_async_await_race(), or oxphp_async_await_any(). For oxphp_async_await_any() timeouts the accessors getPartialErrors(): array<int, \Throwable> and getCancelledPromiseIds(): list<int> are populated; for the other call sites both return []. |
OxPHP\Async\AggregateAsyncException |
OxPHP\Async\AsyncException |
Thrown by oxphp_async_await_any() when every promise rejected. Methods: getErrors(): list<\Throwable> (positional, keyed 0..N-1 by input position), getErrorMap(): array<int, \Throwable> (keyed by promise id), getPromiseIds(): list<int> (input promise ids in order). |
OxPHP\Async\BorrowException |
\Exception |
Error borrowing a value between threads |
OxPHP\Http\Exception\NoActiveRequestException |
\RuntimeException |
Calling oxphp_http_request() outside an active request |
OxPHP\Http\Exception\AsyncContextException |
NoActiveRequestException |
Calling oxphp_http_request() inside an oxphp_async() callback |
OxPHP\Http\Exception\WorkerIdleException |
NoActiveRequestException |
Calling oxphp_http_request() in worker mode between requests |
OxPHP\Decorator\RejectedException |
\Exception |
A decorator rejected a function/method call |
Extension Verification
You can verify that the OxPHP extension is loaded and inspect all registered functions:
<?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
// )The core SAPI functions (through oxphp_register_decorator) come first; the oxphp_async_* and oxphp_apm_* families — and the OxPHP\Profile\* SDK when the profiler is built in — are appended by their plugins during module init. Treat this list as illustrative: the exact set and ordering depend on which plugins are compiled into the build.
Compatibility with PHP-FPM
If your code must run on both OxPHP and PHP-FPM, use fallback wrappers:
<?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
}The oxphp_async() family of functions is always registered in OxPHP, so function_exists('oxphp_async') returns true even when ASYNC_WORKERS=0. When the pool is disabled, calling any async function throws OxPHP\Async\AsyncException. If your code must handle both configurations, catch the exception rather than checking function_exists().
See Also
- HTTP Request API -- object-oriented access to request data via
oxphp_http_request() - Worker Mode -- persistent worker loop and request lifecycle
- Server-Sent Events -- real-time streaming with
oxphp_stream_flush() - Early Response -- background processing with
oxphp_finish_request() - Superglobals -- how OxPHP populates
$_SERVER,$_GET,$_POST, and other superglobals - Distributed Tracing & APM -- W3C Trace Context, OTel export, and the
oxphp_apm_*()SDK - Configuration Reference --
WORKER_MODE_ENABLED,ENTRY_FILE,PHP_WORKERS, and other env vars