本文目录导读:

- 安装信号处理器(核心函数)
- 使用
pcntl_signal_dispatch()检查信号 - 使用
pcntl_async_signals()(PHP 7.1+) - 常见终止信号说明
- 实际应用场景
- 必须在 CLI 下运行
- 完整示例:带资源清理的守护进程
在 PHP 中,终止信号通常指的是 进程终止信号(Process Termination Signals),SIGTERM 或 SIGINT(Ctrl+C),PHP 本身并没有一个叫“终止信号”的内置函数,但你可以通过信号处理 来捕获和处理这些信号,实现优雅退出、资源清理等操作。
以下是 PHP 中与终止信号相关的核心方法和实现:
安装信号处理器(核心函数)
pcntl_signal()
安装一个信号处理器,当进程收到指定信号时,会调用自定义的回调函数。
<?php
declare(ticks = 1); // 低版本 PHP 需要此声明,PHP 7.1+ 不建议用 ticks,推荐使用 pcntl_signal_dispatch()
// 注册信号处理
pcntl_signal(SIGTERM, function ($signo) {
echo "收到 SIGTERM 信号,清理资源...\n";
// 关闭数据库连接、释放文件句柄等
exit; // 或自己决定是否退出
});
pcntl_signal(SIGINT, function ($signo) {
echo "收到 Ctrl+C (SIGINT),正在退出...\n";
exit;
});
echo "PID: " . posix_getpid() . "\n";
echo "等待信号...\n";
while (true) {
// 推荐方式:手动派发待处理的信号
if (function_exists('pcntl_signal_dispatch')) {
pcntl_signal_dispatch();
}
sleep(1);
}
⚠️ 注意:
- 必须在 CLI 模式下运行(
php script.php),Web 模式(FastCGI/FPM)通常不直接接收信号。 declare(ticks = 1)在 PHP 7.1+ 已被弃用,推荐使用pcntl_signal_dispatch()手动触发信号分发。
使用 pcntl_signal_dispatch() 检查信号
适合在 长循环、事件循环 中定期检查是否有待处理的信号。
<?php
pcntl_signal(SIGTERM, function () {
fwrite(STDERR, "收到 SIGTERM,准备退出...\n");
exit;
});
while (true) {
// 你的业务逻辑...
usleep(100000); // 0.1秒
// 每次循环检查并处理信号
pcntl_signal_dispatch();
}
使用 pcntl_async_signals()(PHP 7.1+)
更现代的方式:开启异步信号处理,无需手动 dispatch。
<?php
pcntl_async_signals(true); // 启用异步信号处理
pcntl_signal(SIGTERM, function ($signo) {
echo "Async SIGTERM received, cleaning up...\n";
exit;
});
echo "Running... PID: " . posix_getpid() . "\n";
while (true) {
// 不需要调用 dispatch,系统自动回调
sleep(1);
}
优点:简洁、高效,推荐在 PHP 7.1+ 使用。
常见终止信号说明
| 信号 | 值 | 默认行为 | 触发方式 |
|---|---|---|---|
| SIGTERM | 15 | 终止进程 | kill <pid |
| SIGINT | 2 | 终止进程 | Ctrl+C |
| SIGQUIT | 3 | 终止+core dump | Ctrl+\ |
| SIGHUP | 1 | 终止(或重读取配置) | 终端断开、kill -1 |
| SIGKILL | 9 | 强制杀死 | kill -9 <pid>(无法捕获) |
你无法捕获
SIGKILL和SIGSTOP。
实际应用场景
- 守护进程(Daemon):收到
SIGTERM时,等待当前任务完成后再退出。 - Web Worker(如 ReactPHP、Swoole):收到信号后停止接受新请求,等已有请求处理完毕再关闭。
- 脚本长时间运行:允许用户通过
Ctrl+C优雅退出。
必须在 CLI 下运行
上述所有信号处理仅在 PHP CLI(命令行)下有效。
在 PHP-FPM 或 Apache mod_php 中,进程由服务器管理,通常不能直接捕获信号(因为它们来自 FastCGI 池管理器)。
完整示例:带资源清理的守护进程
<?php
pcntl_async_signals(true);
$running = true;
// 处理终止信号
$cleanup = function () use (&$running) {
fwrite(STDERR, "SIGTERM received. Graceful shutdown...\n");
// 关闭数据库连接、写最后的日志等
$running = false;
};
pcntl_signal(SIGTERM, $cleanup);
pcntl_signal(SIGINT, $cleanup);
echo "Server PID: " . posix_getpid() . "\n";
while ($running) {
// 模拟处理任务
echo "Working...\n";
sleep(2);
}
echo "Bye!\n";
想测试的话,可以:
php daemon.php & # 得到 PID 后,执行 kill <PID> # 发送 SIGTERM # 或按 Ctrl+C 如果在前台运行
- 核心函数:
pcntl_signal()+pcntl_signal_dispatch()或pcntl_async_signals(true)。 - 仅 CLI 模式 有效。
- 常见信号:SIGTERM(kill)、SIGINT(Ctrl+C)。
- 无法捕获:SIGKILL、SIGSTOP。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播