第一步,創(chuàng)建一個(gè)自定義命令類文件,運(yùn)行指令
php think make:command Timing
會(huì)生成一個(gè)app\command\Timing 命令行指令類,根據(jù)實(shí)際項(xiàng)目?jī)?nèi)容修改如下示例:
<?php
/**
* 定時(shí)任務(wù)命令行工具
*
* 本文件定義了一個(gè)ThinkPHP命令行命令,用于執(zhí)行系統(tǒng)定時(shí)任務(wù)。
* 可通過系統(tǒng)crontab配置定期調(diào)用,實(shí)現(xiàn)自動(dòng)化業(yè)務(wù)處理。
*/
// 開啟嚴(yán)格類型模式,確保方法參數(shù)和返回值類型嚴(yán)格匹配,提升代碼健壯性
declare(strict_types=1);
// 定義命令類所在的命名空間,符合ThinkPHP應(yīng)用的組織結(jié)構(gòu)
namespace app\command;
// 引入ThinkPHP命令行基礎(chǔ)類
use think\console\Command; // 命令行命令基類,所有自定義命令必須繼承此類
use think\console\Input; // 輸入處理類,用于獲取命令行參數(shù)和選項(xiàng)
use think\console\Output; // 輸出處理類,用于向控制臺(tái)輸出信息
use think\console\input\Argument; // 參數(shù)定義類,用于定義位置參數(shù)
use think\console\input\Option; // 選項(xiàng)定義類,用于定義命名選項(xiàng)參數(shù)
use think\facade\Log; // 日志門面,用于記錄執(zhí)行日志(可選)
/**
* 定時(shí)任務(wù)執(zhí)行命令類
*
* 該類繼承自ThinkPHP的Command基類,用于創(chuàng)建可被調(diào)用的定時(shí)任務(wù)命令。
* 通過系統(tǒng)cron配置定期執(zhí)行,實(shí)現(xiàn)自動(dòng)化業(yè)務(wù)處理。
*
* @package app\command
*/
class Timing extends Command
{
/**
* 配置命令基本信息
*
* 該方法在命令注冊(cè)時(shí)被框架調(diào)用,用于設(shè)置命令的名稱、描述、參數(shù)和選項(xiàng)等信息。
* 這些信息會(huì)在執(zhí)行 `php think list` 時(shí)顯示在命令列表中。
*
* @return void
*/
protected function configure(): void
{
// 設(shè)置命令名稱,在命令行中通過 `php think timing` 調(diào)用
$this->setName('timing')
// 設(shè)置命令描述,顯示在命令列表中便于識(shí)別命令用途
->setDescription('執(zhí)行系統(tǒng)定時(shí)任務(wù),包括數(shù)據(jù)清理、統(tǒng)計(jì)報(bào)表生成等自動(dòng)化作業(yè)')
// 添加命令參數(shù)定義(示例:可選的執(zhí)行模式參數(shù))
// 參數(shù)格式:Argument::create('參數(shù)名', '模式', '描述', '默認(rèn)值')
// 模式:Argument::REQUIRED(必填) 或 Argument::OPTIONAL(可選)
->addArgument('mode', Argument::OPTIONAL, '任務(wù)執(zhí)行模式(test-測(cè)試模式, force-強(qiáng)制模式)', 'normal')
// 添加命令選項(xiàng)定義(示例:是否跳過某些任務(wù)的選項(xiàng))
// 選項(xiàng)格式:Option::create('選項(xiàng)名', '簡(jiǎn)寫', '模式', '描述', '默認(rèn)值')
// 模式:Option::VALUE_REQUIRED(必須值), Option::VALUE_OPTIONAL(可選值),
// Option::VALUE_NONE(無值,作為開關(guān)使用)
->addOption('skip-clean', null, Option::VALUE_NONE, '跳過數(shù)據(jù)清理任務(wù)')
->addOption('verbose', 'v', Option::VALUE_NONE, '顯示詳細(xì)執(zhí)行信息');
}
/**
* 執(zhí)行命令的主要邏輯
*
* 當(dāng)用戶在命令行中運(yùn)行 `php think timing` 時(shí),該方法會(huì)被自動(dòng)調(diào)用。
* 包含完整的定時(shí)任務(wù)業(yè)務(wù)邏輯,建議將不同任務(wù)模塊化處理。
*
* @param Input $input 輸入對(duì)象,用于獲取命令行輸入的參數(shù)和選項(xiàng)值
* @param Output $output 輸出對(duì)象,用于向控制臺(tái)輸出執(zhí)行信息和結(jié)果
* @return int 返回執(zhí)行狀態(tài)碼:0-成功,1-失?。ㄗ裱璘nix慣例)
*/
protected function execute(Input $input, Output $output): int
{
// 輸出開始執(zhí)行提示信息,使用info樣式顯示綠色文本
$output->writeln('<info>?? 開始執(zhí)行定時(shí)任務(wù)...</info>');
// 獲取命令行參數(shù)和選項(xiàng)值
$executionMode = $input->getArgument('mode'); // 獲取模式參數(shù)
$isSkipClean = $input->getOption('skip-clean'); // 獲取是否跳過清理的選項(xiàng)
$isVerbose = $input->getOption('verbose'); // 獲取是否顯示詳細(xì)信息的選項(xiàng)
// 顯示當(dāng)前執(zhí)行配置(在詳細(xì)模式下顯示)
if ($isVerbose) {
$output->writeln("?? 執(zhí)行模式: {$executionMode}");
$output->writeln("?? 跳過清理: " . ($isSkipClean ? '是' : '否'));
}
try {
// 記錄開始時(shí)間,用于計(jì)算任務(wù)執(zhí)行耗時(shí)
$startTime = microtime(true);
// ======================= 任務(wù)執(zhí)行區(qū)域開始 =======================
// 任務(wù)1: 執(zhí)行數(shù)據(jù)清理(除非指定了跳過清理選項(xiàng))
if (!$isSkipClean) {
$output->writeln('?? 開始執(zhí)行數(shù)據(jù)清理任務(wù)...');
$this->cleanupData(); // 調(diào)用數(shù)據(jù)清理方法
$output->writeln('<comment>? 數(shù)據(jù)清理完成</comment>');
} else {
$output->writeln('<comment>?? 跳過數(shù)據(jù)清理任務(wù)</comment>');
}
// 任務(wù)2: 生成每日統(tǒng)計(jì)報(bào)表
$output->writeln('?? 開始生成統(tǒng)計(jì)報(bào)表...');
$reportResult = $this->generateReports(); // 調(diào)用報(bào)表生成方法
$output->writeln("<comment>? 報(bào)表生成完成: {$reportResult}條記錄</comment>");
// 任務(wù)3: 發(fā)送通知郵件(僅在非測(cè)試模式下執(zhí)行)
if ($executionMode !== 'test') {
$output->writeln('?? 開始發(fā)送通知郵件...');
$sentCount = $this->sendNotifications(); // 調(diào)用郵件發(fā)送方法
$output->writeln("<comment>? 郵件發(fā)送完成: {$sentCount}封</comment>");
}
// ======================= 任務(wù)執(zhí)行區(qū)域結(jié)束 =======================
// 計(jì)算并顯示總執(zhí)行時(shí)間
$executionTime = round(microtime(true) - $startTime, 2);
$output->writeln("<info>?? 所有定時(shí)任務(wù)執(zhí)行完成!耗時(shí): {$executionTime}秒</info>");
// 記錄成功日志(可選)
Log::info("定時(shí)任務(wù)執(zhí)行成功 - 模式: {$executionMode}, 耗時(shí): {$executionTime}秒");
// 返回成功狀態(tài)碼
return 0;
} catch (\Exception $e) {
// 捕獲執(zhí)行過程中拋出的異常
$errorMessage = "? 定時(shí)任務(wù)執(zhí)行失敗: " . $e->getMessage();
// 輸出錯(cuò)誤信息到控制臺(tái)(紅色文本)
$output->writeln("<error>{$errorMessage}</error>");
// 記錄詳細(xì)錯(cuò)誤日志,包含堆棧跟蹤信息
Log::error("定時(shí)任務(wù)執(zhí)行失敗: " . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
]);
// 返回失敗狀態(tài)碼 1
return 1;
}
}
/**
* 執(zhí)行數(shù)據(jù)清理任務(wù)
*
* 清理過期緩存、臨時(shí)文件、無效數(shù)據(jù)等
* 實(shí)際項(xiàng)目中應(yīng)根據(jù)具體業(yè)務(wù)需求實(shí)現(xiàn)
*
* @return void
*/
private function cleanupData(): void
{
// 示例:清理過期緩存
// Cache::clearExpired();
// 示例:刪除臨時(shí)文件
// $this->deleteTempFiles();
// 示例:清理數(shù)據(jù)庫中的軟刪除記錄
// Model::where('delete_time', '<', time() - 30*86400)->delete();
// 模擬清理操作耗時(shí)
sleep(1);
}
/**
* 生成統(tǒng)計(jì)報(bào)表
*
* 生成各種業(yè)務(wù)統(tǒng)計(jì)報(bào)表,如每日訂單統(tǒng)計(jì)、用戶活躍度等
*
* @return int 返回生成的報(bào)表記錄數(shù)
*/
private function generateReports(): int
{
// 示例:生成每日訂單統(tǒng)計(jì)
// $orderCount = Order::whereDate('create_time', date('Y-m-d'))->count();
// 示例:生成用戶活躍度報(bào)表
// $activeUsers = User::where('last_login_time', '>', time() - 86400)->count();
// 模擬報(bào)表生成操作,返回生成的記錄數(shù)
sleep(2);
return 15; // 模擬生成15條報(bào)表記錄
}
/**
* 發(fā)送通知郵件
*
* 向相關(guān)人員發(fā)送任務(wù)執(zhí)行結(jié)果通知
*
* @return int 返回成功發(fā)送的郵件數(shù)量
*/
private function sendNotifications(): int
{
// 示例:發(fā)送郵件通知
// $mailer = new Mailer();
// $sent = $mailer->sendDailyReport();
// 模擬郵件發(fā)送操作
sleep(1);
return 3; // 模擬發(fā)送3封郵件
}
}
第二步,配置config/console.php文件
<?php
return [
'commands' => [
'timing' => 'app\command\Timing',
]
];
第三步,測(cè)試,運(yùn)行命令
php think timing
第四步,添加定時(shí)計(jì)劃任務(wù),具體百度下如何添加計(jì)劃任務(wù)一大堆