PHP curl_multi_info_read函数(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在 PHP 开发中,网络请求是常见的操作场景,无论是调用第三方 API 还是抓取网页数据,都离不开 cURL
库的支持。然而,当需要同时发起多个 HTTP 请求时,传统的单线程方式效率低下,容易导致程序阻塞。此时,PHP curl_multi_info_read
函数便成为优化并发请求的关键工具之一。本文将从基础概念、函数原理、代码示例到实战案例,系统讲解如何通过 curl_multi_info_read
实现高效多线程请求,帮助开发者提升代码性能与用户体验。
一、理解多线程请求与 curl_multi
系列函数
1.1 什么是多线程请求?
多线程请求是指在同一个 PHP 脚本中同时发起多个 HTTP 请求,而非逐个等待每个请求完成。这类似于快递公司同时派送多个包裹,而非按顺序逐个送货。通过这种方式,可以显著缩短总耗时,尤其在需要同时获取多个外部资源时效果显著。
1.2 curl_multi
系列函数的核心作用
PHP 的 curl_multi
系列函数提供了实现多线程请求的能力,其中关键函数包括:
curl_multi_init()
:初始化多线程句柄。curl_multi_add_handle()
:向句柄中添加单个请求的 cURL 句柄。curl_multi_exec()
:执行所有添加的请求,并返回当前执行状态。curl_multi_info_read()
:获取已完成请求的详细信息。
这四个函数协同工作,共同构建了 PHP 多线程请求的完整流程。
二、curl_multi_info_read
函数详解
2.1 函数基础语法
array|bool curl_multi_info_read ( resource $multi_handle , int &$msgs_in_queue )
- 参数说明:
multi_handle
:通过curl_multi_init()
初始化的多线程句柄。msgs_in_queue
:返回队列中剩余未读取的完成请求数量。
- 返回值:
成功时返回关联数组(包含请求结果),失败时返回false
。
2.2 函数工作原理
curl_multi_info_read
的核心作用是从多线程队列中提取已完成请求的信息。它与 curl_multi_exec
配合使用,形成一个“执行-查询”的循环:
curl_multi_exec
持续执行所有未完成的请求;- 当某个请求完成时,它会进入“已完成队列”;
- 开发者通过
curl_multi_info_read
逐个读取该队列中的结果。
比喻解释:
想象一个快递分拣站:
curl_multi_exec
负责将包裹(请求)分发到不同快递员手中;- 完成的包裹会被放入“已送达”货架;
curl_multi_info_read
就是仓库管理员逐个取走货架上的包裹并记录信息。
三、函数返回值的解析
3.1 返回数组的常见字段
调用 curl_multi_info_read
后,返回的数组包含以下关键信息:
| 字段名 | 描述 |
|-----------------|----------------------------------------------------------------------|
| msg
| 始终为 CURLMSG_DONE
,表示请求已完成。 |
| result
| 请求的最终状态码(如 CURLE_OK
表示成功)。 |
| handle
| 完成请求的 cURL 句柄资源,用于后续操作(如 curl_close
)。 |
| http_code
| HTTP 响应状态码(如 200
、404
)。 |
| total_time
| 请求的总耗时(单位:秒,浮点数)。 |
3.2 示例返回值分析
Array
(
[msg] => 1
[result] => 0
[handle] => Resource id #5
[http_code] => 200
[total_time] => 0.234
)
msg=1
表示CURLMSG_DONE
;result=0
表示CURLE_OK
(无错误);http_code=200
说明请求成功;total_time
帮助开发者优化性能瓶颈。
四、代码示例:实现多线程请求
4.1 基础用法示例
// 1. 初始化多线程句柄
$mh = curl_multi_init();
// 2. 创建两个 cURL 句柄并添加到多线程
$urls = [
'https://api.example.com/data1',
'https://api.example.com/data2'
];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
}
// 3. 执行请求并循环检查结果
do {
$status = curl_multi_exec($mh, $active);
} while ($status === CURLM_CALL_MULTI_PERFORM || $active > 0);
// 4. 读取已完成的请求信息
while ($info = curl_multi_info_read($mh)) {
if ($info['msg'] === CURLMSG_DONE) {
$handle = $info['handle'];
$response = curl_multi_getcontent($handle);
echo "请求状态码:" . $info['http_code'] . "\n";
echo "响应内容:" . $response . "\n";
curl_close($handle); // 关闭句柄
}
}
// 5. 关闭多线程句柄
curl_multi_close($mh);
4.2 代码流程解析
- 初始化与添加句柄:通过
curl_multi_init
创建多线程容器,并逐个添加单个请求的句柄。 - 执行与循环检查:
curl_multi_exec
持续执行请求,直到所有请求完成或无活动句柄。 - 读取结果:通过循环调用
curl_multi_info_read
,逐个处理完成的请求数据。 - 资源释放:关闭所有 cURL 句柄和多线程句柄,避免内存泄漏。
五、实战案例:批量获取 API 数据
5.1 场景描述
假设需要同时获取三个天气 API 的数据,但每个 API 的响应时间存在差异。通过 curl_multi_info_read
实现并发请求,最终将结果整合输出。
5.2 完整代码实现
<?php
$mh = curl_multi_init();
$urls = [
'https://api.weather1.com/forecast',
'https://api.weather2.com/forecast',
'https://api.weather3.com/forecast'
];
// 创建并添加所有请求
foreach ($urls as $key => $url) {
$ch[$key] = curl_init($url);
curl_setopt_array($ch[$key], [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5, // 设置超时时间为5秒
]);
curl_multi_add_handle($mh, $ch[$key]);
}
// 执行请求
do {
$status = curl_multi_exec($mh, $active);
} while ($status === CURLM_CALL_MULTI_PERFORM || $active > 0);
// 处理完成的请求
$completed = [];
while ($info = curl_multi_info_read($mh)) {
if ($info['msg'] === CURLMSG_DONE) {
$handle = $info['handle'];
$response = curl_multi_getcontent($handle);
$httpCode = $info['http_code'];
$completed[] = [
'url' => curl_getinfo($handle, CURLINFO_EFFECTIVE_URL),
'status' => $httpCode,
'data' => json_decode($response, true) ?? '请求失败',
'time' => $info['total_time']
];
curl_close($handle);
}
}
// 输出结果
echo "所有请求已完成,总耗时:" . array_sum(array_column($completed, 'time')) . "秒\n";
foreach ($completed as $item) {
echo "URL: " . $item['url'] . "\n";
echo "状态码:" . $item['status'] . "\n";
echo "数据:" . json_encode($item['data'], JSON_UNESCAPED_UNICODE) . "\n\n";
}
curl_multi_close($mh);
5.3 关键点解析
- 超时控制:通过
CURLOPT_TIMEOUT
防止单个请求阻塞整体流程。 - 错误处理:使用
json_decode
的默认值(?? '请求失败'
)捕获解析异常。 - 性能统计:通过
total_time
计算总耗时,帮助优化 API 调用策略。
六、常见问题与解决方案
6.1 问题1:curl_multi_info_read
返回 false
是为什么?
可能原因:
- 队列中已无待读取的完成请求。
- 多线程句柄(
$mh
)未正确初始化或已关闭。
解决方案:
- 确保在
curl_multi_exec
完成后再调用curl_multi_info_read
。 - 在循环中检查返回值,避免重复读取。
while ($info = curl_multi_info_read($mh)) {
// 处理逻辑
}
6.2 问题2:如何处理超时或失败的请求?
策略:
- 在
curl_setopt
中设置CURLOPT_CONNECTTIMEOUT
和CURLOPT_TIMEOUT
。 - 根据返回的
$info['http_code']
或$info['result']
进行条件判断。
if ($info['result'] !== CURLE_OK) {
echo "请求失败,错误代码:" . $info['result'] . "\n";
// 记录日志或重试逻辑
}
结论
通过本文的讲解,读者应已掌握 PHP curl_multi_info_read
函数的核心原理、用法及实际应用场景。该函数是构建高效 PHP 多线程请求的关键工具,尤其在需要批量获取外部资源时,能够显著提升程序性能。未来,随着项目需求的复杂化,开发者可进一步结合协程或异步框架(如 Swoole)实现更高级的并发管理。建议读者通过实际案例练习,逐步掌握多线程编程的最佳实践,为构建高并发系统打下坚实基础。