本文目录导读:

在 PHP 中处理超时涉及多个层面,根据你的应用场景(Web 请求、脚本执行、外部API调用等),有以下几种处理方式:
Web 请求超时
PHP 脚本执行超时
// 设置执行时间限制(秒)
set_time_limit(30); // 30秒
ini_set('max_execution_time', 30);
// 如果设置为0,表示无限执行时间
set_time_limit(0);
客户端请求超时
// 检查是否超时
if (connection_status() != CONNECTION_NORMAL) {
// 客户端断开连接,处理超时
exit('Connection lost');
}
// 设置响应超时
ini_set('max_execution_time', 30);
ini_set('max_input_time', 60);
外部 API/HTTP 请求超时
cURL 超时
function fetchUrl($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5, // 连接超时(秒)
CURLOPT_TIMEOUT => 10, // 整个请求超时(秒)
CURLOPT_TIMEOUT_MS => 10000, // 毫秒级别超时
]);
$response = curl_exec($ch);
$errno = curl_errno($ch);
if ($errno === CURLE_OPERATION_TIMEOUTED) {
curl_close($ch);
throw new Exception('请求超时');
}
curl_close($ch);
return $response;
}
file_get_contents 超时
$ctx = stream_context_create([
'http' => [
'timeout' => 5, // 秒
'ignore_errors' => true,
],
'ssl' => [
'verify_peer' => false,
]
]);
$response = @file_get_contents('https://api.example.com', false, $ctx);
if ($response === false) {
$error = error_get_last();
if (strpos($error['message'], 'timed out') !== false) {
echo "请求超时";
}
}
数据库查询超时
PDO 设置超时
try {
// 设置连接超时(MySQL)
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8',
'user',
'password',
[
PDO::ATTR_TIMEOUT => 5, // 连接超时
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]
);
// 设置查询超时(MySQL 8+)
$pdo->exec("SET SESSION wait_timeout = 10");
$pdo->exec("SET SESSION max_execution_time = 5000"); // 毫秒
} catch (PDOException $e) {
echo "数据库连接超时: " . $e->getMessage();
}
MySQLi 设置超时
$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);
$mysqli->options(MYSQLI_OPT_READ_TIMEOUT, 10);
$mysqli->options(MYSQLI_OPT_WRITE_TIMEOUT, 10);
if (!$mysqli->real_connect($host, $user, $pass, $db)) {
if ($mysqli->connect_errno === 2002) { // 连接超时错误码
echo "数据库连接超时";
}
}
文件上传/下载超时
// 配置文件上传超时
ini_set('max_execution_time', 300);
ini_set('max_input_time', 600);
ini_set('memory_limit', '256M');
ini_set('post_max_size', '10M');
ini_set('upload_max_filesize', '10M');
自定义超时处理机制
使用 pcntl 信号处理(Unix/Linux)
declare(ticks = 1);
function timeoutHandler($signo) {
switch ($signo) {
case SIGALRM:
echo "执行超时,进行清理操作\n";
exit(1);
}
}
pcntl_signal(SIGALRM, 'timeoutHandler');
pcntl_alarm(10); // 10秒后触发SIGALRM
// 你的长任务
while (true) {
// 执行操作
}
// 取消定时器
pcntl_alarm(0);
使用 register_shutdown_function
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
// 处理致命错误(可能包含超时)
echo "脚本因超时或错误终止: " . $error['message'];
// 进行清理操作
}
});
set_time_limit(5);
// 长时间执行的代码
while (true) {
// 业务逻辑
}
异步/并发请求超时
// 使用 Swoole 协程(高性能场景)
Swoole\Coroutine\run(function () {
$timeout = 3;
$result = Swoole\Coroutine\go(function () {
// 需要执行的请求
$client = new Swoole\Coroutine\Http\Client('api.example.com', 443, true);
$client->set(['timeout' => 2]);
$client->get('/endpoint');
return $client->body;
});
if (Swoole\Coroutine\channel()->pop($timeout) === null) {
echo "请求超时";
}
});
综合超时处理类
class TimeoutHandler {
private $startTime;
private $timeout;
public function __construct($timeout) {
$this->startTime = microtime(true);
$this->timeout = $timeout;
}
public function checkTimeout() {
$elapsed = microtime(true) - $this->startTime;
if ($elapsed >= $this->timeout) {
throw new Exception("操作超时,已耗时 " . round($elapsed, 2) . " 秒");
}
}
public function getRemainingTime() {
return $this->timeout - (microtime(true) - $this->startTime);
}
public function setConnectionTimeout($seconds) {
$this->timeout = $seconds;
}
}
// 使用示例
try {
$handler = new TimeoutHandler(10);
// 需要监控的长时间操作
while (true) {
$handler->checkTimeout(); // 检查是否超时
// 执行部分工作
// ...
// 在关键节点检查
if ($handler->getRemainingTime() < 2) {
// 剩余时间不足,提前退出
break;
}
}
} catch (Exception $e) {
echo "超时处理: " . $e->getMessage();
}
最佳实践建议
配置调整(php.ini)
; 生产环境推荐配置 max_execution_time = 60 max_input_time = 120 memory_limit = 256M session.gc_maxlifetime = 1440
队列任务超时(如 Laravel)
// Laravel 队列任务设置超时
class ProcessJob {
public $timeout = 60; // 秒
public $tries = 3; // 重试次数
public function handle() {
// 长时间处理逻辑
}
}
使用缓存机制避免重复超时
// 防止重复执行长时间任务
$lockKey = 'long_task_lock';
if (!apcu_fetch($lockKey)) {
apcu_store($lockKey, true, 300); // 5分钟锁
try {
// 执行长时间任务
set_time_limit(240);
// ...
} finally {
apcu_delete($lockKey);
}
}
总结要点
- 区分场景:Web请求、CLI脚本、外部API调用需要不同的超时策略
- 合理设置:超时时间要根据业务需求设置,不宜过短或过长
- 优雅处理:超时后要能正确清理资源,返回友好的错误信息
- 监控记录:记录超时日志,分析是否需要对超时时间进行调整
- 重试机制:对于不稳定的外部依赖,考虑添加适当的重试策略
选择合适的方法时要考虑你的使用场景:是处理用户请求、后台任务,还是与外部系统交互,对于高并发生产环境,建议结合队列、消息系统或异步框架来管理复杂的超时场景。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播