PHP 函数

OxPHP 通过 oxphp_sapi 扩展注册其函数,该扩展会为服务器执行的每个 PHP 脚本自动加载。无需 extension= 指令,也无需手动加载。此处列出的每个函数从你 PHP 代码的第一行起就可用。

目录

oxphp_http_request()

php
oxphp_http_request(): \OxPHP\Http\Request

返回当前 HTTP 请求的请求对象。该对象以类型化的方式提供对 HTTP 方法、URI、查询参数、解析后的请求体、请求头、cookie、上传文件、客户端 IP 以及请求计时的访问。

返回: 一个 \OxPHP\Http\Request 实例,其数据来自当前 PHP 工作线程中的请求数据。

抛出: 在活动请求之外调用时,会抛出 OxPHP\Http\Exception 命名空间中的异常:

异常 情形
\OxPHP\Http\Exception\WorkerIdleException 工作进程模式,请求之间
\OxPHP\Http\Exception\AsyncContextException oxphp_async() 回调内部
\OxPHP\Http\Exception\NoActiveRequestException 任何其他没有活动请求的上下文

在正常的请求处理代码中,无需进行异常处理。

示例:

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

完整的接口参考请参见 HTTP Request API 文档。

oxphp_superglobals_enabled()

php
oxphp_superglobals_enabled(): bool

返回当前服务器实例是否启用了超全局变量填充。该值反映 SUPERGLOBALS_ENABLED 环境变量,且在服务器生命周期内不会改变。

当为 false 时,$_GET$_POST$_COOKIE$_FILES$_SERVER 均为空数组。HTTP 对象 API(oxphp_http_request())、php://input 以及 PHP 会话函数不受影响。

返回:SUPERGLOBALS_ENABLEDtrue(默认值)时返回 true,否则返回 false

示例:

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

oxphp_request_id()

php
oxphp_request_id(): string

返回当前请求的唯一请求标识符。这与 X-Request-ID 响应头中发送的值相同。如果客户端发送了 X-Request-ID 请求头,OxPHP 会原样透传该值,而不会生成新的值。

返回: 当 OxPHP 生成该 ID 时,返回一个 20 个字符的十六进制字符串(例如 "67890abc12341a2b0042")。当客户端发送了 X-Request-ID 请求头时,该值将原样返回(1–64 个字符,由字母数字加上 -_. 组成)。

示例:

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

oxphp_worker_id()

php
oxphp_worker_id(): int

返回处理当前请求的 PHP 工作线程的从零开始的索引。工作进程索引的范围为 0PHP_WORKERS - 1

返回: 一个标识当前工作线程的整数。

示例:

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

oxphp_server_info()

php
oxphp_server_info(): array

返回一个包含服务器和请求元数据的关联数组。

返回: 一个包含以下键的数组:

类型 说明
version string 服务器版本(例如 "0.10.0"
worker_id int oxphp_worker_id() 相同的值
request_time float 请求开始时的 Unix 时间戳,精确到微秒
worker_mode bool 当前进程是否运行在工作进程模式下

示例:

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

将响应刷新给客户端,并在后台继续执行 PHP。客户端会立即收到完整的 HTTP 响应;脚本会持续运行直到自然退出。这相当于 PHP-FPM 中的 fastcgi_finish_request()

返回: 成功时返回 true,如果在当前请求上已经调用过则返回 false

Note

在脚本结束之前,PHP 工作线程仍会被占用。请让后台工作保持简短,或将繁重的处理交给队列。

示例:

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

oxphp_is_worker()

php
oxphp_is_worker(): bool

返回服务器是否运行在工作进程模式下。当 WORKER_MODE_ENABLED=true 时,工作进程模式将被激活。

返回: 如果运行在工作进程模式下返回 true,在传统模式下返回 false

示例:

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

oxphp_worker()

php
oxphp_worker(callable $handler): bool

进入持久化的工作进程模式循环。OxPHP 会为每个传入的 HTTP 请求调用一次 $handler。在请求之间,一次软重置会清理每个请求的状态——输出缓冲区、请求头和超全局变量——但不会销毁 PHP 堆,因此任何在处理器之外声明的变量都会在多个请求之间保持存在。

参数:

  • $handler — 每个请求调用一次。处理器不接收任何参数。在处理器内部使用超全局变量($_SERVER$_GET$_POST 等)或 oxphp_http_request() 来访问请求数据。

返回: 优雅关闭时返回 true,如果不在工作进程模式下则返回 false

当满足以下任一条件时,工作进程循环将退出:

  • 服务器优雅关闭
  • 处理器连续抛出 3 次未捕获的异常或致命错误
  • 工作进程超过 WORKER_MAX_MEMORY_MIB
  • 应用调用 Worker::scheduleExit()
Note

oxphp_worker() 仅在工作进程模式(WORKER_MODE_ENABLED=true)下有效。在传统模式下,它会记录一条警告并返回 false

示例:

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

返回当前请求是否处于流式模式。流式模式会在首次调用 oxphp_stream_flush() 时激活,或者在 PHP 设置 Content-Type: text/event-stream 时自动激活。

返回: 如果流式模式已激活返回 true,否则返回 false

示例:

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

oxphp_stream_flush()

php
oxphp_stream_flush(): bool

激活流式模式,并将任何已缓冲的输出作为一个 HTTP 分块刷新给客户端。在首次调用时,HTTP 请求头会立即发送,流式传输随即开始。之后的每次调用都会刷新自上次刷新以来写入的输出。

返回: 成功时返回 true,如果已经调用过 oxphp_finish_request() 则返回 false

Note

当 PHP 设置 Content-Type: text/event-stream 时,流式模式也会自动激活。在这种情况下,你可以使用 PHP 内置的 flush(),但要先调用 ob_end_flush() 以绕过 PHP 的输出缓冲层。

示例:

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

oxphp_sleep()

php
oxphp_sleep(float $seconds): void

休眠指定的时长。在运行于纤程中的工作进程模式处理器内部,此调用是协作式的——它会挂起当前纤程,以便在等待期间可以处理其他请求。在纤程之外,它会回退到标准的阻塞式 usleep()

参数:

  • $seconds — 休眠时长,以秒为单位。接受小数值(例如 0.5 表示 500 毫秒)。值为 0 或更小时会立即返回。

返回: void

示例:

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

oxphp_usleep()

php
oxphp_usleep(int $microseconds): void

休眠指定的微秒数。与 oxphp_sleep() 一样,此调用在纤程内部是协作式的,否则会回退到阻塞式 usleep()

参数:

  • $microseconds — 休眠时长,以微秒为单位。值为 0 或更小时会立即返回。

返回: void

示例:

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

oxphp_async()

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

将一个闭包分派到专用的异步工作线程上执行,并立即返回一个 promise ID。调用方无需等待闭包完成即可继续执行。使用 oxphp_async_await() 来获取结果。

参数:

  • $closure — 一个用户定义的 Closure,将在异步工作线程上运行
  • ...$args — 传递给闭包的参数。接受标量值(nullboolintfloatstring)、由这些值组成的数组,以及 OxPHP\Shared\* 实例(唯一可以跨越线程边界的对象)。资源和任何非 Shared 对象都会被拒绝。

返回: 一个整数 promise ID。将其传递给 oxphp_async_await()oxphp_async_await_all()oxphp_async_await_race()oxphp_async_await_any()

抛出: 在以下情况下抛出 OxPHP\Async\AsyncException

  • 异步池被禁用(ASYNC_WORKERS=0)——消息:"Async pool is disabled. Set ASYNC_WORKERS > 0 to enable."
  • 闭包不是用户定义的
  • 异步池已满(所有队列槽位均被占用)
  • 参数或 use 变量中包含对象或资源
Note

通过闭包中的 use 捕获的 use 变量遵循相同的限制——对象和资源会被拒绝。

示例:

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

oxphp_async_await()

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

阻塞直到指定的异步 promise 完成并返回其结果。在工作进程模式的纤程内部,此调用会协作式地挂起当前纤程,而不是阻塞线程。

参数:

  • $promise_id — 由 oxphp_async() 返回的 promise ID
  • $timeout — 等待的最长秒数。0.0 表示无限期等待。默认值:0.0

返回: 异步闭包的返回值。

抛出:

  • 如果异步池被禁用(ASYNC_WORKERS=0),或者异步任务抛出了异常,则抛出 OxPHP\Async\AsyncException
  • 如果超过 $timeout,则抛出 OxPHP\Async\TimeoutException

示例:

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

oxphp_async_await_all()

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

等待数组中的所有 promise,并返回一个将每个 promise ID 映射到其结果的关联数组。promise 按数组顺序等待。

参数:

  • $promise_ids — 一个由 oxphp_async() 返回的整数 promise ID 数组
  • $timeout — 每个 promise 等待的最长秒数。0.0 表示无限期等待。默认值:0.0

返回: 一个关联数组,其中每个键是一个 promise ID(整数),每个值是该 promise 的结果。

抛出:

  • 如果异步池被禁用(ASYNC_WORKERS=0),或者任何 promise 失败,则抛出 OxPHP\Async\AsyncException
  • 如果任何 promise 超过 $timeout,则抛出 OxPHP\Async\TimeoutException

示例:

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

对多个 promise 进行竞速,并返回第一个落定的 promise,无论它是被兑现还是被拒绝。其他 promise 不会被取消——它们会继续运行,并可通过 oxphp_async_await() 继续等待。这是 JavaScript Promise.race 的对应实现。

参数:

  • $promise_ids — 一个由 oxphp_async() 返回的、至少包含一个整数 promise ID 的数组。不能为空。
  • $timeout — 等待任一 promise 落定的最长秒数。0.0 表示无限期等待。默认值:0.0

返回: 一个包含两个键的关联数组:

  • idint)— 胜出者的 promise ID
  • valuemixed)— 胜出 promise 的返回值

抛出:

  • 如果异步池被禁用(ASYNC_WORKERS=0),或者胜出的 promise 被拒绝,则抛出 OxPHP\Async\AsyncException
  • 如果在 $timeout 内没有 promise 落定,则抛出 OxPHP\Async\TimeoutException

示例:

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

oxphp_async_await_any()

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

一旦有一个 promise 被兑现就立即返回。拒绝会被累积起来,只有当每个 promise 都被拒绝时才变得可观察。这是 JavaScript Promise.any 的对应实现——适用于回退/冗余模式,即你希望使用任何一个可用的来源。

参数:

  • $promise_ids — 一个由 oxphp_async() 返回的、至少包含一个整数 promise ID 的数组。不能为空。
  • $timeout — 等待首次兑现的最长秒数。0.0 表示无限期等待。默认值:0.0

返回: 一个包含两个键的关联数组:

  • idint)— 第一个被兑现的 promise 的 ID
  • valuemixed)— 胜出 promise 的返回值

抛出:

  • 如果异步池被禁用(ASYNC_WORKERS=0),则抛出 OxPHP\Async\AsyncException
  • 如果每个 promise 都被拒绝,则抛出 OxPHP\Async\AggregateAsyncException。该异常通过 getErrors()(按位置排列,键为 0..N-1)、getErrorMap()(以 id 为键)和 getPromiseIds() 携带每一个错误。
  • 如果在 $timeout 内没有 promise 被兑现,则抛出 OxPHP\Async\TimeoutExceptiongetPartialErrors() 列出在截止时间前已经被拒绝的 promise;getCancelledPromiseIds() 列出那些尚未落定、因而已被取消的 promise。它们的取消标志已被设置,其接收器也已被丢弃——之后将这些 id 中的任何一个传递给 oxphp_async_await*() 都会抛出 "unknown or already-awaited promise id"。该列表是一份审计记录,而非可恢复工作的队列。

行为:

  • 在胜出时刻仍处于挂起状态的 promise,仍可通过 oxphp_async_await() 单独等待。
  • 在胜出者之前就已被拒绝的 promise 则不可——它们的结果在作为候选错误被累积时已被消费。

示例:

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

oxphp_register_decorator()

php
oxphp_register_decorator(string $class): bool

将一个 PHP 类注册为装饰器,用以包装函数和方法调用。该类必须实现 OxPHP\Decorator\AttributeInterface。一旦注册,OxPHP 会在每次匹配该装饰器 #[Attribute] 目标的函数或方法调用前后调用装饰器的 before()after() 钩子。

参数:

  • $class — 要注册的装饰器的完全限定类名

返回: 成功时返回 true,如果该类不存在或未实现 OxPHP\Decorator\AttributeInterface 则返回 false

示例:

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

在一个命名的 span 内部执行回调。span 在回调运行前打开,并在其返回后关闭。保留供未来增强的回调集成使用。

参数:

  • $name — span 名称
  • $callback — 在 span 内部执行的可调用对象
  • $attributes — 可选的字符串键值属性关联数组

返回: void

oxphp_apm_start()

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

打开一个新的 span,并返回一个供后续引用的本地 ID。该 span 成为当前活动 span 的子级(如果没有活动 span,则成为请求根 span 的子级)。使用 oxphp_apm_end() 来关闭它。

参数:

  • $name — span 名称(例如 "cache.warm""payment.process"
  • $attributes — 可选的字符串键值属性关联数组,在创建时设置到 span 上

返回: 一个整数本地 span ID。将其传递给 oxphp_apm_end()oxphp_apm_attribute() 或其他接受 $span_id 的函数。当 APM 被禁用时返回 0

示例:

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

oxphp_apm_end()

php
oxphp_apm_end(int $span_id): void

关闭由 oxphp_apm_start() 打开的 span。span 的结束时间被记录下来,并从活动栈移入已完成列表,等待导出。

参数:

  • $span_id — 由 oxphp_apm_start() 返回的本地 span ID

返回: void

Note

始终以相反的顺序关闭 span。如果你先打开 span A 再打开 span B,则应先关闭 B 再关闭 A。未关闭的 span 会在请求结束时自动关闭,并标记为 oxphp.span.leaked=true

oxphp_apm_attribute()

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

在一个 span 上设置一个键值属性。值会被转换为字符串。如果未提供 $span_id,该属性会被添加到当前活动的 span 上。

参数:

  • $key — 属性键(例如 "user.id""cache.hit"
  • $value — 属性值(string、int、float、bool 或 null —— 会被转换为字符串)
  • $span_id — 可选的本地 span ID。省略时以当前 span 为目标

返回: void

示例:

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

oxphp_apm_event()

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

在一个 span 上记录一个带时间戳的事件。事件适用于记录 span 生命周期内的离散事件(例如缓存未命中、重试尝试、授权检查)。

参数:

  • $name — 事件名称(例如 "cache.miss""retry"
  • $attributes — 可选的字符串键值事件属性关联数组
  • $span_id — 可选的本地 span ID。省略时以当前 span 为目标

返回: void

示例:

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

oxphp_apm_error()

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

将一个 span 的状态标记为错误(状态码 2)。用它来标记发生了异常或失败的 span。

参数:

  • $exception — 异常或错误(用于提供上下文;无论其类型如何都会设置状态)
  • $span_id — 可选的本地 span ID。省略时以当前 span 为目标

返回: void

示例:

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

oxphp_apm_status()

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

设置一个 span 的状态码和可选的描述。

参数:

  • $code — 状态码:0 = 未设置,1 = 正常,2 = 错误
  • $description — 可选的人类可读状态描述
  • $span_id — 可选的本地 span ID。省略时以当前 span 为目标

返回: void

示例:

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

oxphp_apm_trace_id()

php
oxphp_apm_trace_id(): string

返回当前请求追踪上下文的 W3C 追踪 ID(32 个十六进制字符)。这与 $_SERVER['OXPHP_TRACE_ID'] 的值相同,且无需超全局变量即可获取。

返回: 一个 32 个字符的十六进制追踪 ID 字符串。当 APM 被禁用或没有活动的追踪上下文时,返回空字符串。

示例:

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

oxphp_apm_span_id()

php
oxphp_apm_span_id(): string

返回当前活动 span 的 span ID(16 个十六进制字符)。如果存在嵌套的 span,则返回最内层已打开 span 的 ID。

返回: 一个 16 个字符的十六进制 span ID 字符串。当没有活动的 span 时,返回空字符串。

oxphp_apm_header()

php
oxphp_apm_header(): string

返回当前 span 上下文的 W3C traceparent 请求头值。用它将追踪上下文传播到下游的 HTTP 调用。

返回: 一个格式为 00-{trace_id}-{span_id}-01 的字符串。当没有活动的追踪上下文时,返回空字符串。

示例:

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

OxPHP\Profile\is_active()

php
OxPHP\Profile\is_active(): bool

当当前请求的性能分析捕获处于活动状态时返回 true——即性能分析器已被触发(通过请求头、cookie、查询参数或采样率),且捕获未通过 pause() 暂停。

适用于保护那些仅在开启性能分析时才应运行的昂贵埋点。

返回: bool

示例:

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

OxPHP\Profile\start()

php
OxPHP\Profile\start(): void

以编程方式为当前请求的剩余部分启用性能分析捕获,即使在 RINIT 时没有触发器被触发。将性能分析模式设置为 PROFILE_ALL 并清除暂停标志。

如果已有一个性能分析在不同模式下处于活动状态,此调用会将其提升——在较低模式下已收集的任何 span 都会被丢弃,以使捕获到的性能分析在内部保持一致。当你想在不依赖触发器的情况下将某个特定代码路径纳入性能分析时,可使用此调用。

返回: void

示例:

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

OxPHP\Profile\stop()

php
OxPHP\Profile\stop(): void

禁止本次请求进一步捕获 span。当前打开的 span 会在 PHP 从中返回时自然关闭,因此调用栈保持平衡——只是不再记录新的 span。

返回: void

示例:

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

OxPHP\Profile\pause()

php
OxPHP\Profile\pause(): void

stop() 的软性变体。效果相同(设置暂停标志);区别在于意图——pause() 表示捕获稍后会通过 resume() 恢复,而 stop() 则不会。

返回: void

OxPHP\Profile\resume()

php
OxPHP\Profile\resume(): void

清除由 pause()stop() 设置的暂停标志。性能分析模式本身不会改变——如果它从未被启用,则 resume() 不会产生任何可观察的效果。

返回: void

示例:

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

OxPHP\Profile\mark()

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

将一个 Mark 事件附加到最顶层已打开的 span 上,并可附带一个可选的属性包。当没有打开的 span 时(例如性能分析未激活,或在任何被埋点的帧之外的请求顶层调用 mark()),此调用为空操作。

属性的键和值会被强制转换为字符串;非字符串值会变成空字符串。

参数:

  • $label — 事件的简短人类可读名称(例如 "cache.miss""db.slow_query"
  • $attrs — 可选的 array<string, scalar>,为附加到事件的键值对

返回: void

示例:

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

OxPHP\Profile\metric()

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

将一个 metric.<name> 属性追加到当前打开的 span 上。当没有打开的 span 时,此调用为空操作。

mark()(它创建一个离散事件)不同,metric() 写入现有 span 的属性集——适用于记录与周围操作相关联的数值观测(获取的行数、处理的字节数、重试次数)。

参数:

  • $name — 指标标识符;将以 metric.<name> 的形式存储
  • $value — 数值(会被强制转换为 float

返回: void

示例:

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

类与接口

oxphp_sapi 扩展注册了以下类:

HTTP

说明
OxPHP\Http\Request oxphp_http_request() 返回的请求对象。final——不可被继承。
OxPHP\Http\Attributes 可变的请求属性容器(供中间件使用)。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。公共属性:targetclassmethodfunctionobjectIdrequestIdtraceId。方法:getParams(): arraygetResult(): mixedhasResult(): bool。完整参考请参见 装饰器

追踪

说明
OxPHP\Apm\Trace 用于自动创建 span 的内置属性。可应用于函数或方法。

异步

说明
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 当每个 promise 都被拒绝时由 oxphp_async_await_any() 抛出。方法:getErrors(): list<\Throwable>(按位置排列,按输入位置键为 0..N-1)、getErrorMap(): array<int, \Throwable>(按 promise id 为键)、getPromiseIds(): list<int>(按顺序排列的输入 promise id)。
OxPHP\Async\BorrowException \Exception 在线程间借用值时出错
OxPHP\Http\Exception\NoActiveRequestException \RuntimeException 在活动请求之外调用 oxphp_http_request()
OxPHP\Http\Exception\AsyncContextException NoActiveRequestException oxphp_async() 回调内部调用 oxphp_http_request()
OxPHP\Http\Exception\WorkerIdleException NoActiveRequestException 在工作进程模式的请求之间调用 oxphp_http_request()
OxPHP\Decorator\RejectedException \Exception 装饰器拒绝了一个函数/方法调用

扩展验证

你可以验证 OxPHP 扩展是否已加载,并查看所有已注册的函数:

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

核心 SAPI 函数(直到 oxphp_register_decorator)排在最前;oxphp_async_*oxphp_apm_* 系列——以及当性能分析器被内置时的 OxPHP\Profile\* SDK——由其插件在模块初始化期间追加。请将此列表视为示意:确切的集合和顺序取决于哪些插件被编译进了该构建版本。

与 PHP-FPM 的兼容性

如果你的代码必须同时在 OxPHP 和 PHP-FPM 上运行,请使用回退包装器:

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

oxphp_async() 系列函数在 OxPHP 中始终会被注册,因此即使在 ASYNC_WORKERS=0 时,function_exists('oxphp_async') 也返回 true。当异步池被禁用时,调用任何异步函数都会抛出 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 导出以及 oxphp_apm_*() SDK
  • 配置参考 —— WORKER_MODE_ENABLEDENTRY_FILEPHP_WORKERS 及其他环境变量
code