本文目录导读:

在 PHP 中实现 cURL 并发请求主要有以下几种方法,我来详细介绍:
*curlmulti 函数(最常用)**
这是 PHP 官方提供的并发处理方案:
<?php
// 准备多个请求
$urls = [
'https://api.example.com/users',
'https://api.example.com/posts',
'https://api.example.com/comments'
];
// 创建 cURL 多重句柄
$mh = curl_multi_init();
$handles = [];
// 为每个 URL 创建单独的 cURL 句柄
foreach ($urls as $key => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
// 添加到多重句柄
curl_multi_add_handle($mh, $ch);
$handles[$key] = $ch;
}
// 执行并发请求
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh); // 等待活动连接
} while ($running > 0);
// 获取结果
$results = [];
foreach ($handles as $key => $ch) {
$results[$key] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
// 关闭多重句柄
curl_multi_close($mh);
// 输出结果
print_r($results);
?>
封装成可复用函数
<?php
/**
* 并发请求函数
* @param array $requests 请求配置数组
* @return array 响应结果
*/
function multiCurlRequest(array $requests) {
$mh = curl_multi_init();
$handles = [];
foreach ($requests as $key => $request) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 设置请求方法
$method = isset($request['method']) ? strtoupper($request['method']) : 'GET';
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if (isset($request['post_data'])) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $request['post_data']);
}
}
// 设置请求头
if (isset($request['headers'])) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $request['headers']);
}
// 设置超时
$timeout = isset($request['timeout']) ? $request['timeout'] : 30;
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
// 是否SSL验证
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_multi_add_handle($mh, $ch);
$handles[$key] = $ch;
}
// 执行并发请求
$running = null;
do {
$status = curl_multi_exec($mh, $running);
if ($running) {
curl_multi_select($mh);
}
} while ($running > 0 && $status === CURLM_OK);
// 收集结果
$results = [];
foreach ($handles as $key => $ch) {
$results[$key] = [
'content' => curl_multi_getcontent($ch),
'error' => curl_error($ch),
'errno' => curl_errno($ch),
'info' => curl_getinfo($ch)
];
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
// 使用示例
$requests = [
'user' => [
'url' => 'https://api.example.com/user/1',
'method' => 'GET',
'timeout' => 10
],
'post' => [
'url' => 'https://api.example.com/post/create',
'method' => 'POST',
'post_data' => ['title' => 'Hello', 'content' => 'World'],
'timeout' => 15
],
'search' => [
'url' => 'https://api.example.com/search?q=php',
'method' => 'GET',
'headers' => ['Authorization: Bearer token']
]
];
$results = multiCurlRequest($requests);
foreach ($results as $key => $result) {
echo "请求 {$key} 结果:\n";
echo "状态码: " . $result['info']['http_code'] . "\n";
echo "内容: " . $result['content'] . "\n\n";
}
?>
使用生成器模式(PHP 5.5+)
<?php
// 使用 Generator 处理流式响应
class MultiCurlHandler {
private $mh;
private $channels = [];
public function __construct() {
$this->mh = curl_multi_init();
}
public function addRequest($name, $url, $options = []) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
foreach ($options as $opt => $value) {
curl_setopt($ch, $opt, $value);
}
curl_multi_add_handle($this->mh, $ch);
$this->channels[$name] = $ch;
return $this;
}
public function execute() {
$running = null;
do {
curl_multi_exec($this->mh, $running);
curl_multi_select($this->mh);
} while ($running > 0);
$results = [];
foreach ($this->channels as $name => $ch) {
$results[$name] = curl_multi_getcontent($ch);
curl_multi_remove_handle($this->mh, $ch);
curl_close($ch);
}
curl_multi_close($this->mh);
return $results;
}
}
// 使用
$handler = new MultiCurlHandler();
$handler->addRequest('google', 'https://www.google.com')
->addRequest('baidu', 'https://www.baidu.com')
->addRequest('github', 'https://api.github.com');
$results = $handler->execute();
print_r($results);
?>
使用 Guzzle 库(推荐)
如果允许使用第三方库,Guzzle 提供了更优雅的方式:
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client(['timeout' => 10]);
// 创建多个请求
$promises = [
'users' => $client->getAsync('https://api.example.com/users'),
'posts' => $client->getAsync('https://api.example.com/posts'),
'comments' => $client->getAsync('https://api.example.com/comments'),
];
// 等待所有请求完成
$results = Promise\Utils::settle($promises)->wait();
// 处理结果
foreach ($results as $key => $result) {
if ($result['state'] === 'fulfilled') {
echo "{$key}: " . $result['value']->getBody() . "\n";
} else {
echo "{$key} 失败: " . $result['reason'] . "\n";
}
}
?>
处理动态添加请求
<?php
// 分批处理大量请求
function processManyRequests(array $urls, $batchSize = 10) {
$allResults = [];
foreach (array_chunk($urls, $batchSize) as $batch) {
$mh = curl_multi_init();
$handles = [];
foreach ($batch as $key => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[$key] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $key => $ch) {
$allResults[$key] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
}
return $allResults;
}
?>
注意事项
- 超时设置:一定要设置超时,避免请求无限等待
- 错误处理:检查
curl_error()确保请求成功 - 资源清理:使用完要关闭所有句柄
- 限制并发数:避免一次性发起过多请求
- SSL 验证:生产环境建议启用 SSL 验证
选择哪种方式取决于你的需求和项目环境,如果是新项目,推荐使用 Guzzle;如果不想引入依赖,使用 curlmulti* 就足够了。