cron 表达式是含 6 或 7 个字段的空格分隔字符串,依次为秒、分、时、日、月、周、年(可选),各字段有明确取值范围和特殊字符(如 *、?、-、/、l、w 等),用于精确控制定时任务触发时间。

别从 Cron 表达式语法开始学,先确保 crontab -e 能真正跑通一个 PHP 脚本——90% 的“学不会”其实是环境没通,不是语法没懂。
为什么 php /path/to/script.php 在终端能跑,crontab 却静默失败
这是最常卡住人的第一步。Cron 启动时的环境和你登录 shell 完全不同:没有 $PATH、不加载 ~/.bashrc、当前工作目录是 root 用户家目录(不是你的项目目录)。
- 用绝对路径调用 PHP:
/usr/bin/php或/opt/php/bin/php,别只写php;可用which php确认 - 脚本里所有文件操作(如
require、file_put_contents)必须用绝对路径,或在脚本开头chdir(__DIR__) - 在 crontab 文件顶部加两行声明环境:
PATH=/usr/local/bin:/usr/bin:/bin SHELL=/bin/bash
- 重定向输出是唯一调试手段:
* * * * * /usr/bin/php /var/www/task.php >> /tmp/cron_debug.log 2>&1,然后tail -f /tmp/cron_debug.log
cron-expression 库怎么用才不踩坑
别自己 parse Cron 字符串。生产环境直接上 dragonmantank/cron-expression,它处理了 mon-fri、1-5/2、@daily 这些边界情况,且无框架依赖。
- 安装:
composer require dragonmantank/cron-expression - 判断某时刻是否触发:
$cron->isDue(new DateTime('2026-05-12 09:30:00'))—— 注意必须传DateTime实例,传字符串会静默返回 false - 时区必须对齐:
date_default_timezone_set('Asia/Shanghai')和new DateTime('...','Asia/Shanghai')要一致,否则0 2 * * *在 UTC 服务器上实际是北京时间上午 10 点 - 秒级支持需显式指定字段:
CronExpression::factory('*/5 * * * * *', CronExpression::MINUTE_FIELD),默认只认 5 字段
PHP 代码里动态管理定时任务,为什么推荐 cron/cron 而不是手写调度器
手写 while + sleep 的“伪定时”在生产环境等于埋雷:进程意外退出无人拉起、多实例竞争、时间漂移、无法热更新规则。
-
cron/cron是轻量级封装,它不替代系统 cron,而是让所有调度逻辑集中在 PHP 代码里,配合一行系统级* * * * * /usr/bin/php /path/to/cron-runner.php触发 - 好处是:任务定义可 git 版本控制、可按环境开关(
if (APP_ENV === 'prod'))、可统一注入 DI 容器、日志和错误处理与主项目一致 - 注意它的
run()方法是单次执行判断,不是常驻进程 —— 所以仍需系统 cron 每分钟拉一次,不能删掉那行crontab - 避免和 Laravel Scheduler 混用:后者本质也是同理,但强耦合框架;若项目无框架,
cron/cron更干净
真正难的不是写对 0 3 * * *,而是让这个表达式在 3 台不同配置的服务器上、不同 PHP 版本下、不同用户权限下,每次执行都拿到相同的环境、路径、时区和错误反馈。先打通这一环,语法只是查表的事。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











