PHP curl_multi_remove_handle 函数
最后修改日期:2025 年 4 月 11 日
PHP curl_multi_remove_handle 函数从一个 multi handle 中移除一个 cURL handle。它用于并发请求处理,以便在 multi-handle 上下文中管理单个 handle。
基本定义
curl_multi_remove_handle 函数从一个 multi handle 中移除一个标准的 cURL handle。这通常在 handle 完成其请求后进行。该函数成功时返回 0,失败时返回 CURLM_* 错误代码。
语法:curl_multi_remove_handle(CurlMultiHandle $multi_handle, CurlHandle $handle): int。两个 handle 都必须是有效且已初始化的。始终在关闭 handle 之前移除它们,以防止资源泄露。
基本的 Multi Handle 移除
此示例演示了从 multi handle 中移除 handle 的基本用法。
<?php
declare(strict_types=1);
$mh = curl_multi_init();
$ch1 = curl_init('https://api.example.com/data1');
$ch2 = curl_init('https://api.example.com/data2');
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Execute the multi handle
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running > 0);
// Remove handles after completion
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
curl_close($ch1);
curl_close($ch2);
此代码创建一个 multi handle 并添加两个 cURL handle。在执行所有请求后,它在关闭每个 handle 之前正确地移除它们。这可以防止资源泄露并确保干净的清理。
选择性 Handle 移除
此示例展示了如何根据响应状态选择性地移除 handle。
<?php
declare(strict_types=1);
$mh = curl_multi_init();
$handles = [];
for ($i = 1; $i <= 5; $i++) {
$ch = curl_init("https://jsonplaceholder.typicode.com/posts/$i");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[] = $ch;
}
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $handle) {
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$response = curl_multi_getcontent($handle);
echo "Success: " . substr($response, 0, 50) . "...\n";
}
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
curl_multi_close($mh);
我们创建多个请求并并发处理它们。完成后,我们检查每个响应状态,并且只输出成功的响应。无论状态如何,所有 handle 都被正确移除和关闭。
移除时的错误处理
此示例演示了移除 handle 时的正确错误处理。
<?php
declare(strict_types=1);
$mh = curl_multi_init();
$ch1 = curl_init('https://invalid.url');
$ch2 = curl_init('https://jsonplaceholder.typicode.com/posts/1');
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
// Process and remove handles
$handles = [$ch1, $ch2];
foreach ($handles as $handle) {
$errno = curl_errno($handle);
if ($errno !== 0) {
echo "Error: " . curl_error($handle) . "\n";
} else {
echo "Success: " . substr(curl_multi_getcontent($handle), 0, 50) . "...\n";
}
$result = curl_multi_remove_handle($mh, $handle);
if ($result !== CURLM_OK) {
echo "Warning: Failed to remove handle (" . curl_multi_strerror($result) . ")\n";
}
curl_close($handle);
}
curl_multi_close($mh);
我们处理成功和失败的请求。代码检查 cURL 错误,并验证移除操作是否成功。这确保了在生产环境中具有强大的错误处理能力。
动态 Handle 管理
此示例展示了在执行过程中动态添加和移除 handle。
<?php
declare(strict_types=1);
$mh = curl_multi_init();
$activeHandles = 0;
function addRequest($mh, &$activeHandles, $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$activeHandles++;
return $ch;
}
// Initial requests
$ch1 = addRequest($mh, $activeHandles, 'https://jsonplaceholder.typicode.com/posts/1');
$ch2 = addRequest($mh, $activeHandles, 'https://jsonplaceholder.typicode.com/posts/2');
do {
curl_multi_exec($mh, $running);
// Check for completed requests
while ($info = curl_multi_info_read($mh)) {
if ($info['msg'] === CURLMSG_DONE) {
$handle = $info['handle'];
echo "Completed: " . curl_getinfo($handle, CURLINFO_EFFECTIVE_URL) . "\n";
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
$activeHandles--;
// Add new request when one completes
if ($activeHandles < 2) {
$newId = rand(3, 10);
addRequest($mh, $activeHandles, "https://jsonplaceholder.typicode.com/posts/$newId");
}
}
}
curl_multi_select($mh);
} while ($activeHandles > 0);
curl_multi_close($mh);
此代码维护一个活动请求池。当一个请求完成时,它会被移除,然后添加一个新的请求。此模式对于有速率限制的 API 或处理大量 URL 非常有用。
复杂的 Multi Handle 场景
此示例演示了一个包含不同请求类型的复杂场景。
<?php
declare(strict_types=1);
$mh = curl_multi_init();
$handles = [];
// Create GET requests
for ($i = 1; $i <= 3; $i++) {
$ch = curl_init("https://jsonplaceholder.typicode.com/posts/$i");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[] = ['type' => 'GET', 'handle' => $ch];
}
// Create POST request
$postData = json_encode(['title' => 'foo', 'body' => 'bar', 'userId' => 1]);
$ch = curl_init("https://jsonplaceholder.typicode.com/posts");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
]);
curl_multi_add_handle($mh, $ch);
$handles[] = ['type' => 'POST', 'handle' => $ch];
// Process all requests
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
// Process responses and clean up
foreach ($handles as $item) {
$ch = $item['handle'];
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "{$item['type']} request to " . curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
echo " returned $httpCode\n";
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
此示例在同一个 multi handle 中混合了 GET 和 POST 请求。每个请求都与其类型一起跟踪,以便正确处理。执行后,所有 handle 都被正确移除和关闭,展示了全面的资源管理。
最佳实践
- 始终移除 Handle: 在关闭之前移除,以防止泄露。
- 检查移除结果: 验证 curl_multi_remove_handle 是否成功。
- 顺序很重要: 在关闭 handle 之前移除它们。
- 错误处理: 同时检查执行和移除错误。
- 资源跟踪: 在复杂场景中跟踪 handle。
来源
PHP curl_multi_remove_handle 文档
本教程通过实际示例介绍了 PHP curl_multi_remove_handle 函数,展示了其在各种并发请求场景中的用法。