php无原生定时器,最简定时逻辑需用while(true)死循环配合sleep()实现,但仅适用于开发调试或低频轻量任务;必须设set_time_limit(0)、加日志、避免web上下文,并推荐用supervisor等工具管理进程而非手动fork。

用 PHP 写死循环 + sleep 实现最简定时逻辑
PHP 本身没有内置的“定时任务调度器”,想脱离 cron 或系统计划任务,本质是让一个 PHP 进程自己扛起周期性执行的责任。最直接的方式就是写个无限循环,靠 sleep() 控制间隔。
但要注意:这不是“优雅方案”,而是“能跑通”的底线做法。适合开发调试、低频轻量任务(比如每 5 分钟拉一次配置、每小时清理一次临时文件),不适用于高精度或高可靠性场景。
-
while (true)必须包裹在脚本顶层,不能放在 Web 请求上下文中(否则请求超时就中断了) - 每次循环开始前建议加
gc_collect_cycles(),防止长期运行内存缓慢增长 - 务必用
set_time_limit(0)禁用超时,否则默认 30 秒会 kill 掉进程 - 推荐加日志记录,比如每次执行前写一行
file_put_contents('log.txt', date('c') . " run\n", FILE_APPEND);
用 pcntl_fork 避免阻塞主进程(仅 Linux/macOS)
如果这个定时脚本要和其它服务共存(比如你不想它占着一个终端/SSH 连接),就得让它“后台化”。pcntl_fork() 是最轻量的分离手段——父进程退出,子进程继续跑循环。
注意:pcntl 扩展默认不启用,需确认已编译并开启;Windows 完全不支持,别白费劲。
- fork 后子进程要调用
posix_setsid()脱离终端会话,否则关掉 SSH 还是会被 kill - 子进程需重定向
STDIN/STDOUT/STDERR到/dev/null,否则可能卡住 - 父进程 exit 前最好记录子进程 PID 到文件,方便后续
kill管理 - 别忘了在循环里加
pcntl_signal_dispatch()和pcntl_signal(SIGTERM, ...),否则kill $pid不生效
用 Supervisor 管理 PHP 守护进程(生产推荐)
手动 fork + pid 文件管理太容易出错。真实项目里,应该交由进程管理工具兜底。supervisor 是最常用选择:它负责启动、崩溃重启、日志收集、状态查看,而你的 PHP 只管写好那个 while 循环就行。
关键不是“PHP 怎么定时”,而是“怎么让 PHP 进程不死”。Supervisor 就是干这个的。
- 配置里
command=php /path/to/your/cron.php,别加&或后台符号 - 设
autostart=true和autorestart=true,机器重启或脚本异常退出都能恢复 -
stdout_logfile和stderr_logfile必须配,不然看不到错误输出 - 避免在 PHP 脚本里再 fork —— Supervisor 管的是最外层进程,多层 fork 会让它失去控制力
为什么不要自己实现“分布式定时”或“精确到秒”
看到有人用 Redis ZSET 存时间戳+任务名,再轮询 pop,还号称“分布式 Cron”——这种方案在单机小流量下能凑合,但实际踩坑极多:
- 轮询间隔若设 1 秒,Redis QPS 就恒定 1;设 100ms,QPS 就飙到 10,纯属自造压力
- 多个实例同时 pop 同一个任务,没加 Lua 原子操作就会重复执行
- PHP 的
microtime(true)在容器或虚拟机里可能漂移,所谓“秒级精度”根本不可靠 - 真正需要分布式调度,请直接上
xxl-job、elastic-job或云厂商的定时函数,别拿 PHP 硬扛
定时任务的复杂度不在“怎么触发”,而在“怎么保证只触发一次、不丢、不错、可追溯”。这些事 PHP 单进程天生不擅长,硬搞只会把问题从运维转移到代码里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











