本文目录导读:

- 服务器Cron(Linux) / 任务计划程序(Windows) ⭐ 最推荐
- PHP原生实现(适合无cron权限的虚拟主机)
- 使用第三方库(推荐生产环境)
- 消息队列方案(适合高并发)
- 使用 Workerman(适合常驻任务)
- 框架集成方案
- 最佳实践建议
在PHP项目中实现定时任务,主要有以下几种主流方案,每种适用于不同场景:
服务器Cron(Linux) / 任务计划程序(Windows) ⭐ 最推荐
Linux Cron
# 编辑crontab crontab -e # 每5分钟执行一次 */5 * * * * /usr/bin/php /path/to/your/script.php # 每天凌晨2点执行 0 2 * * * /usr/bin/php /path/to/your/script.php # 每月1号执行 0 0 1 * * /usr/bin/php /path/to/your/script.php
脚本示例(script.php)
<?php
// 防止超时
set_time_limit(0);
// 记录开始时间
$startTime = date('Y-m-d H:i:s');
file_put_contents('/tmp/cron.log', "开始执行: {$startTime}\n", FILE_APPEND);
// 执行你的任务逻辑
try {
// 数据库清理
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$db->exec("DELETE FROM temp_data WHERE created_at < NOW() - INTERVAL 7 DAY");
// 发送邮件通知
// sendEmails();
file_put_contents('/tmp/cron.log', "执行成功\n", FILE_APPEND);
} catch (Exception $e) {
file_put_contents('/tmp/cron.log', "错误: " . $e->getMessage() . "\n", FILE_APPEND);
}
PHP原生实现(适合无cron权限的虚拟主机)
方案A:每次请求触发检查
<?php
// 在入口文件(如index.php)顶部加入
class TaskScheduler {
private $tasks = [];
public function addTask($name, $interval, $callback) {
$this->tasks[$name] = [
'interval' => $interval, // 秒
'callback' => $callback,
'last_run' => $this->getLastRunTime($name)
];
}
public function run() {
foreach ($this->tasks as $name => $task) {
$nextRun = $task['last_run'] + $task['interval'];
if (time() >= $nextRun) {
call_user_func($task['callback']);
$this->updateLastRunTime($name);
}
}
}
private function getLastRunTime($name) {
// 从文件或数据库读取上次执行时间
$file = "/tmp/scheduler_{$name}.txt";
return file_exists($file) ? (int)file_get_contents($file) : 0;
}
private function updateLastRunTime($name) {
file_put_contents("/tmp/scheduler_{$name}.txt", time());
}
}
// 使用
$scheduler = new TaskScheduler();
$scheduler->addTask('clean_temp', 3600, function() {
// 每小时清理临时数据
echo "清理临时数据...\n";
});
// 在请求处理末尾执行
$scheduler->run();
方案B:独立进程运行
<?php
// cron_daemon.php - 后台守护进程
class CronDaemon {
private $running = true;
private $tasks = [];
public function addTask($name, $interval, $callback) {
$this->tasks[$name] = [
'interval' => $interval,
'callback' => $callback,
'last_run' => 0
];
}
public function start() {
while ($this->running) {
foreach ($this->tasks as $name => &$task) {
if (time() - $task['last_run'] >= $task['interval']) {
echo "[".date('Y-m-d H:i:s')."] 执行任务: {$name}\n";
call_user_func($task['callback']);
$task['last_run'] = time();
}
}
sleep(1); // 每秒检查一次
}
}
public function stop() {
$this->running = false;
}
}
// 运行
$daemon = new CronDaemon();
$daemon->addTask('clean_temp', 3600, function() {
// 任务内容
});
$daemon->start();
使用第三方库(推荐生产环境)
使用 cron-expression 库
composer require dragonmantank/cron-expression
// 使用
use Cron\CronExpression;
$cron = new CronExpression('*/5 * * * *');
if ($cron->isDue()) {
echo "该执行任务了";
// 执行任务
}
使用 php-cron-scheduler
composer require peppeocchi/php-cron-scheduler
// scheduler.php
require 'vendor/autoload.php';
use GO\Scheduler;
$scheduler = new Scheduler();
// 添加任务
$scheduler->php('path/to/script.php', [], 'my_task', [
'traits' => [GO\Job\Job::TRAIT_RUN_IN_BACKGROUND]
])->everyMinute(5);
$scheduler->call(function() {
echo "自定义任务执行中...";
})->daily();
$scheduler->run();
消息队列方案(适合高并发)
// 使用 Redis + PHP 实现延迟队列
class RedisDelayQueue {
private $redis;
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function addTask($taskId, $delaySeconds, $callback) {
$executeTime = time() + $delaySeconds;
$this->redis->zAdd('delay_queue', $executeTime, json_encode([
'id' => $taskId,
'callback' => $callback,
'params' => []
]));
}
public function processTasks() {
while (true) {
// 获取到期的任务
$tasks = $this->redis->zRangeByScore('delay_queue', '-inf', time());
foreach ($tasks as $task) {
$taskData = json_decode($task, true);
// 移除已处理的任务
$this->redis->zRem('delay_queue', $task);
// 执行任务
call_user_func($taskData['callback'], $taskData['params']);
}
usleep(100000); // 100ms
}
}
}
// 使用
$queue = new RedisDelayQueue();
$queue->addTask('email_reminder', 3600, function() {
echo "发送提醒邮件...";
});
$queue->processTasks();
使用 Workerman(适合常驻任务)
composer require workerman/workerman
// timer.php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Lib\Timer;
$worker = new Worker();
$worker->onWorkerStart = function() {
// 每10秒执行一次
$timerId = Timer::add(10, function() {
echo "定时任务执行中...\n";
// 执行任务逻辑
});
// 每天凌晨执行
Timer::add(86400, function() {
echo "每日任务执行\n";
}, [], true); // true表示只执行一次
};
Worker::runAll();
框架集成方案
ThinkPHP
// 在 config/cron.php 配置
return [
'cron' => [
// 每分钟检查任务
'check_order' => [
'type' => 'callable',
'callable' => function() {
// 检查超时订单
},
'next_time' => time(),
'interval' => 60,
],
],
];
Laravel
// App\Console\Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:send')->daily();
$schedule->job(new SendEmailsJob)->everyMinute();
$schedule->call(function () {
// 执行任务
})->hourly();
}
// 运行调度器
php artisan schedule:run
最佳实践建议
-
生产环境优先使用Cron - 最稳定、资源占用最低
-
任务加锁 - 防止任务重叠执行
$lockFile = '/tmp/my_task.lock'; if (file_exists($lockFile) && (time() - filemtime($lockFile)) < 300) { exit("任务正在执行中,跳过\n"); } file_put_contents($lockFile, time()); // 执行任务... unlink($lockFile); -
日志记录 - 记录执行结果和错误
-
异常处理 - 捕获所有可能的异常
-
资源清理 - 及时释放数据库连接、文件句柄等
-
监控告警 - 对长时间未执行的任务发送警报
选择合适的方案取决于你的项目规模、服务器权限和具体需求,对于大多数项目,Linux Cron + PHP脚本 是最简单可靠的方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播