ThinkPHP5定时任务必须由外部调度器(如crontab)触发,核心是创建继承thinkconsoleCommand的命令类:置于application/command/下,命名空间为appcommand,在configure()中用setName()定义命令名,在execute()中编写业务逻辑并用$output->writeln()输出,且须在application/command.php中注册该类完整命名空间。

ThinkPHP5 没有内置的「定时函数文件」概念,tp5 本身不提供类似 setInterval 或后台常驻定时器的能力;所有稳定可用的定时任务,都必须靠外部调度器(如 Linux crontab、宝塔计划任务、Windows 任务计划程序)触发命令行执行,再由 TP5 的 Command 类承接逻辑。
怎么写一个可被 crontab 调用的 TP5 定时任务类
核心是继承 thinkconsoleCommand,实现 configure() 和 execute() 方法。这个类不是“函数文件”,而是一个命令行指令封装体。
-
configure()中必须调用$this->setName('xxx'),这个名字就是后续在终端输入php think xxx时用的命令名 -
execute()是真正干活的地方,所有业务逻辑(查数据库、发消息、写日志)都放这里,不要直接 echo,用$output->writeln()输出便于日志追踪 - 类文件建议放在
application/command/下(路径可自定义,但需同步注册),命名如DeviceCheck.php - 务必在
application/command.php中返回该类完整命名空间,例如:return ['appcommandDeviceCheck'];
示例片段(application/command/DeviceCheck.php):
<?php namespace appcommand;
<p>use thinkconsoleCommand;
use thinkconsoleInput;
use thinkconsoleOutput;
use thinkDb;<p>class DeviceCheck extends Command
{
protected function configure()
{
$this->setName('device:check')
->setDescription('检查离线设备并推送告警');
}</p><pre class="brush:php;toolbar:false;">protected function execute(Input $input, Output $output)
{
$offline = Db::name('device')
->where('last_heartbeat', 'select();
if ($offline) {
// 调用飞书推送逻辑...
$output->writeln('发现 ' . count($offline) . ' 台离线设备');
}
}}
为什么不能直接在函数里写 sleep + while 循环
TP5 命令行脚本默认是非守护进程模式,执行完就退出。手动写 while(true) { ... sleep(120); } 看似能“定时”,但实际会带来严重问题:
- 进程无法被
crontab正常管理,容易堆积僵尸进程 - 没有超时控制,一次卡死会导致后续所有任务停摆
- 无法平滑重启或 reload 配置(比如改了告警阈值要生效,得 kill 进程再启)
- 日志混杂、无明确开始/结束标记,排查困难
所以官方和生产环境都禁止这种写法——定时行为交给系统级调度器,业务逻辑只负责“单次执行”。
crontab 调用时最常踩的三个坑
即使 php think device:check 在命令行能跑通,放到 crontab 里也大概率失败,原因集中在环境隔离上:
- PHP 路径不一致:
which php查到的是用户环境路径,crontab默认用/usr/bin/php,务必写绝对路径,例如/usr/local/bin/php - 工作目录错误:crontab 不自动 cd 到项目根目录,必须显式
cd /var/www/mytp5 &&,否则加载配置、日志路径、数据库连接都会出错 - 环境变量缺失:
crontab不读取~/.bashrc,导致找不到 Composer 自动加载、或某些扩展(如pdo_mysql)不可用;可在 crontab 条目开头加PATH=...补全,或统一用完整路径调用
正确 crontab 条目示例(每 2 分钟执行一次):
*/2 * * * * cd /var/www/mytp5 && /usr/local/bin/php think device:check >> /var/www/mytp5/runtime/log/device_check.log 2>&1
宝塔或 Windows 下怎么配才不丢日志
宝塔面板的「计划任务」本质也是封装 crontab,但界面操作更直观;Windows 则依赖 .bat + 任务计划程序。关键共性是:必须显式重定向输出。
- 不加
>>重定向,标准输出和错误会发到系统邮箱(多数服务器未配邮件服务,结果就是“静默失败”) - 推荐把 stdout 和 stderr 都合并写入项目内日志文件,路径用绝对路径,且确保 web 用户(如
www)对该文件有写权限 - Windows 下注意
.bat文件里 PHP 路径要用反斜杠或双正斜杠,例如:"C:\php\php.exe" "D:/www/mytp5/think" device:check
日志文件位置建议统一放在 runtime/log/ 下,和 TP5 自身日志同源,方便集中轮转和清理。











