PHP 怎么PHP 终止信号

wen PHP项目 1

本文目录导读:

PHP 怎么PHP 终止信号

  1. 安装信号处理器(核心函数)
  2. 使用 pcntl_signal_dispatch() 检查信号
  3. 使用 pcntl_async_signals()(PHP 7.1+)
  4. 常见终止信号说明
  5. 实际应用场景
  6. 必须在 CLI 下运行
  7. 完整示例:带资源清理的守护进程

在 PHP 中,终止信号通常指的是 进程终止信号(Process Termination Signals)SIGTERMSIGINT(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>(无法捕获)

你无法捕获 SIGKILLSIGSTOP


实际应用场景

  • 守护进程(Daemon):收到 SIGTERM 时,等待当前任务完成后再退出。
  • Web Worker(如 ReactPHP、Swoole):收到信号后停止接受新请求,等已有请求处理完毕再关闭。
  • 脚本长时间运行:允许用户通过 Ctrl+C 优雅退出。

必须在 CLI 下运行

上述所有信号处理仅在 PHP CLI(命令行)下有效。
PHP-FPMApache 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。

抱歉,评论功能暂时关闭!