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()

php
oxphp_http_request(): \OxPHP\Http\Request

Returns 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
<?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()

php
oxphp_superglobals_enabled(): bool

Returns 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
<?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

Returns 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
<?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

Returns 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
<?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

Returns 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
<?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()

php
oxphp_finish_request(): bool

Flushes 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.

Note

The PHP worker thread remains occupied until the script finishes. Keep background work short or offload heavy processing to a queue.

Example:

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

Returns 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
<?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

Enters 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.) or oxphp_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()
Note

oxphp_worker() only works in worker mode (WORKER_MODE_ENABLED=true). In traditional mode it logs a warning and returns false.

Example:

worker.php
<?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()

php
oxphp_is_streaming(): bool

Returns 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
<?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

Activates 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.

Note

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
<?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()

php
oxphp_sleep(float $seconds): void

Sleeps 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.5 for 500 milliseconds). Values of 0 or less return immediately.

Returns: void

Example:

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

Sleeps 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 of 0 or less return immediately.

Returns: void

Example:

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

Dispatches 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-defined Closure to run on an async worker thread
  • ...$args — Arguments to pass to the closure. Scalar values (null, bool, int, float, string), arrays of those, and OxPHP\Shared\* instances (the only objects that may cross the thread boundary) are accepted. Resources and any non-Shared object 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
Note

Use-vars captured via use in the closure follow the same restrictions — objects and resources are rejected.

Example:

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

Blocks 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 by oxphp_async()
  • $timeout — Maximum seconds to wait. 0.0 means wait indefinitely. Default: 0.0

Returns: The return value of the async closure.

Throws:

  • OxPHP\Async\AsyncException if the async pool is disabled (ASYNC_WORKERS=0), or if the async task threw an exception
  • OxPHP\Async\TimeoutException if $timeout is exceeded

Example:

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

Awaits 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 by oxphp_async()
  • $timeout — Maximum seconds to wait per promise. 0.0 means 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\AsyncException if the async pool is disabled (ASYNC_WORKERS=0), or if any promise fails
  • OxPHP\Async\TimeoutException if any promise exceeds $timeout

Example:

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

Races 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 by oxphp_async(). Must not be empty.
  • $timeout — Maximum seconds to wait for any promise to settle. 0.0 means wait indefinitely. Default: 0.0

Returns: An associative array with two keys:

  • id (int) — The promise ID of the winner
  • value (mixed) — The return value of the winning promise

Throws:

  • OxPHP\Async\AsyncException if the async pool is disabled (ASYNC_WORKERS=0), or if the winning promise rejected
  • OxPHP\Async\TimeoutException if no promise settles within $timeout

Example:

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

Returns 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 by oxphp_async(). Must not be empty.
  • $timeout — Maximum seconds to wait for the first fulfillment. 0.0 means wait indefinitely. Default: 0.0

Returns: An associative array with two keys:

  • id (int) — The promise ID of the first fulfilled promise
  • value (mixed) — The return value of the winning promise

Throws:

  • OxPHP\Async\AsyncException if the async pool is disabled (ASYNC_WORKERS=0)
  • OxPHP\Async\AggregateAsyncException if every promise rejected. The exception carries every error via getErrors() (positional, keyed 0..N-1), getErrorMap() (id-keyed), and getPromiseIds().
  • OxPHP\Async\TimeoutException if 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 to oxphp_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
<?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

Registers 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
<?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): void

Executes 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()

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

Opens 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
<?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

Closes 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 by oxphp_apm_start()

Returns: void

Note

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()

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

Sets 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
<?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

Records 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
<?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

Marks 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
<?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

Sets 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
<?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

Returns 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
<?php $traceId = oxphp_apm_trace_id(); error_log("Processing request in trace {$traceId}");

oxphp_apm_span_id()

php
oxphp_apm_span_id(): string

Returns 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()

php
oxphp_apm_header(): string

Returns 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
<?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

Returns 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
<?php if (OxPHP\Profile\is_active()) { OxPHP\Profile\mark('checkpoint.before_query'); }

OxPHP\Profile\start()

php
OxPHP\Profile\start(): void

Programmatically 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
<?php if ($request->header('x-debug') === 'on') { OxPHP\Profile\start(); }

OxPHP\Profile\stop()

php
OxPHP\Profile\stop(): void

Disables 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
<?php OxPHP\Profile\start(); expensive_work(); OxPHP\Profile\stop(); non_profiled_work();

OxPHP\Profile\pause()

php
OxPHP\Profile\pause(): void

Soft 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()

php
OxPHP\Profile\resume(): void

Clears 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
<?php OxPHP\Profile\pause(); $secret = decrypt_payload($data); OxPHP\Profile\resume();

OxPHP\Profile\mark()

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

Attaches 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 — optional array<string, scalar> of key/value pairs attached to the event

Returns: void.

Example:

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

Appends 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 as metric.<name>
  • $value — numeric value (coerced to float)

Returns: void.

Example:

php
<?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
<?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

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
<?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

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

code