PHP 中如何运行定时(cron)任务?
PHP 跑定时任务的标准姿势:写好脚本后用系统 crontab 调 php CLI 执行;附 shebang 直接执行写法、Laravel 调度器简介、权限与常见问题。
PHP 本身没有内置调度器,标准做法:把任务写成 PHP 脚本,用系统 crontab 按周期调 php /path/to/script.php 执行。 框架项目(Laravel/Symfony)则可以用内置调度器收口所有任务到一条 cron 规则。
1. 写任务脚本
<?php
// /opt/jobs/send_reminders.php
$users = getPendingUsers();
foreach ($users as $user) {
mail($user['email'], 'Reminder', "Hello, {$user['name']}!");
}
echo date('c') . " sent " . count($users) . " reminders\n";
2. 权限设置
chmod +x /opt/jobs/send_reminders.php # 若要直接执行
3. 注册 crontab
# 每小时执行一次
0 * * * * /usr/bin/php /opt/jobs/send_reminders.php >> /var/log/reminders.log 2>&1
要点:
- 用绝对路径调 PHP CLI:cron 环境 PATH 很窄,
/usr/bin/php写全最稳(which php确认位置)。 - 输出重定向到日志:排错全靠它。
- 注意 CLI 与 FPM 的 php.ini 可能不同:扩展、内存限制在两套配置里分别生效,脚本里用到的扩展要确认 CLI 也加载了。
加 shebang 直接执行
脚本首行写解释器路径后,crontab 里可以不写 php:
#!/usr/bin/php
<?php
// ...
0 * * * * /opt/jobs/send_reminders.php >> /var/log/reminders.log 2>&1
4. 框架方案:Laravel 任务调度
Laravel 把所有任务收口在 routes/console.php(或 Kernel.php):
Schedule::command('emails:send')->hourly();
Schedule::job(new GenerateReport)->dailyAt('02:30');
系统 crontab 只需一条入口规则:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
调度定义进版本库、随代码部署,比散落在各台机器的 crontab 好管理得多。
观测云对照
PHP 定时任务常见两类故障:脚本 fatal error 和"没按计划跑"。两类都该收敛到日志里——脚本内用结构化日志记录开始/结束/异常,DataKit 采集到观测云,用 Pipeline 把 status=error 的任务名提取出来做告警;再给关键任务配心跳监控:预期窗口内没出现成功日志就通知。
常见问题(FAQ)
Q:浏览器访问脚本能跑,cron 里就报错?
A:九成是 CLI 与 FPM 配置差异(扩展没加载、路径不同)。php -m、php --ini 对比两套环境,脚本里用绝对路径。
Q:任务要跑很久会超时吗?
A:CLI 模式默认 max_execution_time 为 0(不限时),但脚本里显式 set_time_limit() 过的会生效;长任务建议加断点续跑能力。
Q:多个 PHP 版本共存怎么指定?
A:crontab 里写具体版本的二进制路径,如 /usr/bin/php8.2 /opt/jobs/task.php。