ThinkPHP6 本身不内置“每月执行一次”的调度器,但可通过 Linux crontab 调用自定义指令(如 report:monthly)实现每月定时执行;也可用 shell 脚本处理复杂日期逻辑(如每月首个工作日),或借助 think-crontab 扩展统一管理多周期任务。

ThinkPHP6 本身不内置“每月执行一次”的调度器,但结合 Linux crontab 或自定义指令 + shell 脚本,可以稳定、精准地实现每月定时执行(比如每月10号凌晨2点跑一次)。关键不是框架能不能“每月触发”,而是如何把业务逻辑封装好,并交给系统级调度器按需调用。
用 crontab 直接调用自定义指令(推荐)
这是最常用、最可靠的方式。先在 ThinkPHP6 中写一个命令行指令,再用 crontab 设定每月时间点。
- 在
app/command/下创建指令类,例如MonthlyReport.php,configure()中设名为report:monthly -
execute()方法里写实际逻辑:生成报表、发邮件、同步数据等 - 服务器上执行
crontab -e,添加一行:0 2 10 * * /usr/bin/php /var/www/myproject/think report:monthly >> /var/log/monthly-report.log 2>&1
表示:每月10日 2:00 执行 - 注意确认
/usr/bin/php是真实 PHP 路径(可用which php查),且think文件有可执行权限
用 shell 脚本做日期判断(适合复杂条件)
当需要“每月第一个工作日”或“每月最后一天”这类非标准日期时,crontab 原生表达式不够用,可借助 shell 脚本动态判断。
- 新建脚本
/path/to/monthly.sh,开头获取当前日期:day=$(date +%-d)、month=$(date +%-m) - 判断是否为每月1号:
if [[ "$day" -eq "1" ]]; then php /var/www/myproject/think report:monthly; fi - 再用 crontab 每天凌晨0:01 触发该脚本:
1 0 * * * /bin/bash /path/to/monthly.sh - 这样既保持 crontab 简洁,又把日期逻辑收口在脚本里,便于调试和复用
用第三方扩展集中管理(适合多任务场景)
如果项目里有多个月度、周度、分钟级任务混在一起,建议用 top-think/think-crontab 这类扩展,把所有计划写在配置文件中,统一维护。
立即学习“PHP免费学习笔记(深入)”;
- 安装:
composer require top-think/think-crontab - 在
config/crontab.php中配置:'tasks' => [ ['task' => \app\task\MonthlyCleanup::class, 'expression' => '0 3 15 * *'] ]
(表示每月15日 3:00 执行) - 启动服务:
php think crontab:start,它会常驻运行并按规则触发 - 优势是配置全在代码里,部署时无需额外改服务器 crontab,适合 CI/CD 流程
注意事项和常见坑
每月任务看似简单,但几个细节容易出问题:
-
时区要对齐:服务器系统时区(
timedatectl status)必须和业务预期一致,否则可能“看起来没执行” -
日志路径要可写:crontab 默认以
root或指定用户身份运行,确保runtime/log或自定义日志目录有对应权限 -
避免重复执行:加进程锁或检查 PID(如 shell 脚本中用
ps -ef | grep ...)防止上月任务未结束,本月又启动 -
测试要模拟真实环境:别只手动跑
php think xxx,一定要用run-parts或临时改 crontab 时间验证整条链路



















