PHP curl_multi_init 函数
最后修改日期:2025 年 4 月 11 日
PHP 的 curl_multi_init 函数创建一个多 cURL 句柄。它允许异步处理多个 cURL 句柄。这对于高效地进行并行 HTTP 请求非常有用。
基本定义
curl_multi_init 函数初始化一个新的多 cURL 句柄。它返回一个可以与其他 curl_multi 函数一起使用的资源。此句柄管理多个单独的 cURL 句柄。
语法:curl_multi_init(): CurlMultiHandle。该函数不接受任何参数,并返回一个多 cURL 句柄。完成后务必使用 curl_multi_close() 进行清理。
基本并行请求
此示例演示了两个并行 HTTP GET 请求。
<?php
declare(strict_types=1);
$urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $ch) {
echo curl_multi_getcontent($ch) . "\n";
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
此代码同时获取两个帖子。我们为每个 URL 创建单独的句柄并将它们添加到多句柄中。循环处理所有请求直至完成。最后,我们检索并输出响应。
使用回调处理响应
此示例展示了如何使用回调来处理完成的响应。
<?php
declare(strict_types=1);
$urls = [
"https://jsonplaceholder.typicode.com/users/1",
"https://jsonplaceholder.typicode.com/users/2",
"https://jsonplaceholder.typicode.com/users/3"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$processed = 0;
do {
curl_multi_exec($mh, $running);
while ($info = curl_multi_info_read($mh)) {
$ch = $info['handle'];
$content = curl_multi_getcontent($ch);
$index = array_search($ch, $handles, true);
echo "Response $index: " . substr($content, 0, 50) . "...\n";
$processed++;
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
if ($running) {
curl_multi_select($mh);
}
} while ($running || $processed < count($urls));
curl_multi_close($mh);
我们使用 curl_multi_info_read 随着响应可用而处理它们。每个已完成的请求都会触发我们的回调逻辑。这种方法比等待所有请求完成更有效。我们跟踪已处理的请求以确保我们处理所有响应。
为并行请求设置超时
此示例演示了为并行请求设置单个超时。
<?php
declare(strict_types=1);
$urls = [
["url" => "https://httpbin.org/delay/2", "timeout" => 3],
["url" => "https://httpbin.org/delay/5", "timeout" => 1]
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $item) {
$ch = curl_init($item['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $item['timeout']);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $i => $ch) {
$errno = curl_errno($ch);
if ($errno === CURLE_OPERATION_TIMEDOUT) {
echo "Request $i timed out\n";
} else {
echo "Request $i completed: " .
substr(curl_multi_getcontent($ch), 0, 30) . "...\n";
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
我们为每个请求设置了不同的超时。第二个请求将在 1 秒后超时,而第一个请求将成功完成。我们使用 curl_errno 检查超时错误。这种模式对于处理慢响应非常有用。
处理大量 URL
此示例展示了如何有效地处理具有并发控制的大量 URL。
<?php
declare(strict_types=1);
function fetchUrls(array $urls, int $concurrency = 5): array {
$mh = curl_multi_init();
$results = [];
$active = [];
// Initialize first batch
for ($i = 0; $i < min($concurrency, count($urls)); $i++) {
$ch = curl_init($urls[$i]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$active[$i] = true;
}
$nextUrl = $concurrency;
$processed = 0;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
while ($info = curl_multi_info_read($mh)) {
$ch = $info['handle'];
$index = array_search($ch, $active, true);
if ($index !== false) {
$results[$index] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
$processed++;
// Add next URL if available
if ($nextUrl < count($urls)) {
$ch = curl_init($urls[$nextUrl]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$active[$nextUrl] = $ch;
$nextUrl++;
}
}
}
} while ($running || $processed < count($urls));
curl_multi_close($mh);
return $results;
}
$urls = array_fill(0, 20, "https://jsonplaceholder.typicode.com/posts/1");
$results = fetchUrls($urls, 5);
echo "Fetched " . count($results) . " responses\n";
此实现分批处理 URL 以控制并发。我们维护一个活动连接池并替换已完成的连接。该函数按顺序返回所有响应。这种方法可以防止因过多的并发请求而导致服务器过载。
并行请求中的错误处理
此示例演示了并行请求的全面错误处理。
<?php
declare(strict_types=1);
$urls = [
"https://valid.example.com/api",
"https://invalid.example.com/api",
"https://timeout.example.com/api"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_multi_add_handle($mh, $ch);
$handles[$i] = [
'handle' => $ch,
'url' => $url
];
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $i => $item) {
$ch = $item['handle'];
$errno = curl_errno($ch);
if ($errno) {
echo "Request $i failed (" . $item['url'] . "): " .
curl_error($ch) . "\n";
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode >= 200 && $httpCode < 300) {
echo "Request $i succeeded: " .
substr(curl_multi_getcontent($ch), 0, 50) . "...\n";
} else {
echo "Request $i returned HTTP $httpCode\n";
}
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
我们为每个请求实现了健壮的错误检查。代码检查 cURL 错误、HTTP 状态码和超时。每次失败都会记录有关出错内容的详细信息。成功响应会照常处理。
最佳实践
- 并发控制:限制并发连接。
- 错误处理:同时检查 cURL 和 HTTP 错误。
- 资源清理:始终删除和关闭句柄。
- 超时设置:为每个请求设置合理的超时。
- 内存管理:随到随处理响应。
来源
本教程介绍了 PHP curl_multi_init 函数,并通过实际示例展示了并行请求处理。这些示例演示了各种实际场景和最佳实践。