php 实现守护进程
守护进程的基本概念
守护进程(Daemon)是在后台运行、不受终端控制的长期存活进程,通常用于执行周期性任务或服务。PHP 可以通过以下方式实现守护进程。
使用 pcntl_fork 创建子进程
通过 pcntl_fork 创建子进程,父进程退出,子进程继续运行并脱离终端控制:
$pid = pcntl_fork();
if ($pid == -1) {
die("Could not fork");
} elseif ($pid) {
exit(); // 父进程退出
}
// 子进程继续执行
调用 posix_setsid 创建新会话
调用 posix_setsid 使子进程成为会话组长,脱离终端关联:

if (posix_setsid() == -1) {
die("Could not detach from terminal");
}
关闭标准输入输出
关闭标准输入、输出和错误流,避免与终端交互:
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
设置 umask 避免权限问题
修改 umask 确保文件权限不受限制:

umask(0);
更改工作目录
避免占用挂载目录,通常切换到根目录:
chdir('/');
处理信号防止意外终止
注册信号处理器,处理 SIGTERM 等信号:
pcntl_signal(SIGTERM, function ($signo) {
exit();
});
循环执行任务逻辑
守护进程通常包含一个无限循环执行核心任务:
while (true) {
// 执行任务逻辑
sleep(1); // 避免 CPU 占用过高
}
完整示例代码
<?php
// 创建子进程
$pid = pcntl_fork();
if ($pid == -1) {
die("Could not fork");
} elseif ($pid) {
exit(); // 父进程退出
}
// 脱离终端控制
if (posix_setsid() == -1) {
die("Could not detach from terminal");
}
// 关闭标准流
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
// 设置权限掩码
umask(0);
// 更改工作目录
chdir('/');
// 信号处理
pcntl_signal(SIGTERM, function ($signo) {
exit();
});
// 主循环
while (true) {
file_put_contents('/tmp/daemon.log', date('Y-m-d H:i:s') . "\n", FILE_APPEND);
sleep(5);
}
注意事项
- 需确保 PHP 已安装
pcntl和posix扩展。 - 避免在循环中占用过高 CPU,可通过
sleep或usleep控制执行频率。 - 日志记录建议使用
syslog或文件,而非标准输出。 - 可通过
supervisord或systemd管理守护进程,增强可靠性。






