ZetCode

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 的基本用法。

basic_removal.php
<?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。

selective_removal.php
<?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 时的正确错误处理。

error_handling.php
<?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。

dynamic_management.php
<?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 场景

此示例演示了一个包含不同请求类型的复杂场景。

complex_scenario.php
<?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 都被正确移除和关闭,展示了全面的资源管理。

最佳实践

来源

PHP curl_multi_remove_handle 文档

本教程通过实际示例介绍了 PHP curl_multi_remove_handle 函数,展示了其在各种并发请求场景中的用法。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了超过 1400 篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

所有 PHP cURL 教程列表。