pcntl_alarm 基于 Unix SIGALRM 信号实现秒级定时,需配合 pcntl_signal 捕获并抛出异常才能中断函数;仅限 CLI 环境,不支持毫秒精度,每次调用覆盖前次定时器。

pcntl\_alarm 的基本原理
pcntl\_alarm 是 PHP 提供的基于 Unix 信号的定时机制,它会在指定秒数后向当前进程发送 SIGALRM 信号。该函数不支持毫秒级精度,最小单位为 1 秒,且每次调用会覆盖前一次未触发的定时器。
配合 pcntl\_signal 实现超时中断
仅调用 pcntl\_alarm 不会自动中断运行中的函数,必须配合 pcntl\_signal 捕获 SIGALRM,并在信号处理器中主动抛出异常或修改状态,才能实现“熔断”效果。
- 需在调用前启用 pcntl 扩展(编译时开启 --enable-pcntl)
- 信号处理器中不宜执行复杂逻辑,推荐仅设置标志位或 throw Exception
- 被中断的函数需处于可中断状态(如未阻塞在 C 层系统调用中,否则信号可能延迟投递)
一个安全可用的超时封装示例
以下是一个兼顾错误恢复与信号清理的实用封装:
function timeout_call(callable $func, int $seconds, ...$args) {
$oldHandler = pcntl_signal_get_handler(SIGALRM);
$timedOut = false;
pcntl_signal(SIGALRM, function ($sig) use (&$timedOut) {
$timedOut = true;
throw new RuntimeException('Function execution timed out');
});
pcntl_alarm($seconds);
try {
$result = $func(...$args);
pcntl_alarm(0); // 清除定时器
pcntl_signal(SIGALRM, $oldHandler); // 恢复原 handler
return $result;
} catch (Throwable $e) {
pcntl_alarm(0);
pcntl_signal(SIGALRM, $oldHandler);
if ($timedOut) {
throw $e;
}
throw $e;
}
}
// 使用示例
try {
$data = timeout_call('file_get_contents', 3, 'https://api.example.com/long-task');
} catch (RuntimeException $e) {
// 熔断处理:返回默认值、记录日志、降级逻辑等
$data = ['status' => 'fallback'];
}
注意事项与常见陷阱
该机制在 CLI 模式下有效,Web SAPI(如 Apache、FPM)中不可靠甚至被禁用,因信号行为受服务器模型限制。
立即学习“PHP免费学习笔记(深入)”;
- PHP 的某些内置函数(如 stream_socket_client、curl_exec)有自身超时参数,优先使用它们而非信号熔断
- 多线程环境(如 pthreads)不适用,pcntl 仅适用于单进程 Unix 风格环境
- 嵌套调用 alarm 时需手动管理重置,避免误触发
- 信号处理期间不应调用非异步信号安全函数(如 echo、error_log),否则可能导致崩溃



















