ZetCode

PHP curl_multi_close 函数

最后修改日期:2025 年 4 月 11 日

PHP 的 curl_multi_close 函数用于关闭一组 cURL 句柄。它用于在同时执行多个 cURL 请求后清理资源。此函数是 PHP cURL 多接口的一部分。

基本定义

curl_multi_close 函数关闭一个 cURL 多句柄并释放所有关联的资源。它以一个由 curl_multi_init() 创建的 cURL 多句柄作为其唯一参数。

语法:curl_multi_close(CurlMultiHandle $multi_handle): void。调用此函数后,多句柄将无法再使用。务必在使用完毕后关闭多句柄,以防止内存泄漏。

基础多请求

此示例演示了如何进行多个请求并关闭句柄。

basic_multi.php
<?php

declare(strict_types=1);

$urls = [
    "https://jsonplaceholder.typicode.com/posts/1",
    "https://jsonplaceholder.typicode.com/posts/2",
    "https://jsonplaceholder.typicode.com/posts/3"
];

$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;
}

do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

foreach ($handles as $ch) {
    echo curl_multi_getcontent($ch) . "\n";
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

curl_multi_close($mh);

此代码同时获取三个帖子。我们创建单独的句柄,将它们添加到多句柄中,然后执行它们。获取内容后,我们会妥善清理所有资源。

多请求中的错误处理

此示例展示了多 cURL 请求的错误处理。

error_handling.php
<?php

declare(strict_types=1);

$urls = [
    "https://jsonplaceholder.typicode.com/posts/1",
    "https://invalid.url",
    "https://jsonplaceholder.typicode.com/posts/3"
];

$mh = curl_multi_init();
$handles = [];

foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_multi_add_handle($mh, $ch);
    $handles[$url] = $ch;
}

do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

foreach ($handles as $url =>  $ch) {
    if (curl_errno($ch)) {
        echo "Error for $url: " . curl_error($ch) . "\n";
    } else {
        echo "Success for $url\n";
    }
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

curl_multi_close($mh);

我们故意包含一个无效 URL 来演示错误处理。每个句柄在执行后都会进行错误检查。在处理完所有请求后,多句柄会被妥善关闭。

并行 API 请求

此示例展示了如何并行从多个 API 获取数据。

parallel_apis.php
<?php

declare(strict_types=1);

$apis = [
    "users" =>  "https://jsonplaceholder.typicode.com/users/1",
    "posts" =>  "https://jsonplaceholder.typicode.com/posts/1",
    "comments" =>  "https://jsonplaceholder.typicode.com/comments/1"
];

$mh = curl_multi_init();
$handles = [];

foreach ($apis as $name =>  $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($mh, $ch);
    $handles[$name] = $ch;
}

do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

$results = [];
foreach ($handles as $name =>  $ch) {
    $results[$name] = json_decode(curl_multi_getcontent($ch), true);
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

curl_multi_close($mh);

print_r($results);

我们同时从三个不同的 API 端点获取数据。结果存储在一个关联数组中,并带有有意义的键。处理完响应后,所有句柄都会被妥善清理。

为多请求设置自定义标头

此示例演示了为多个请求设置自定义标头。

multi_headers.php
<?php

declare(strict_types=1);

$urls = [
    "https://api.example.com/resource1",
    "https://api.example.com/resource2"
];

$headers = [
    'Authorization: Bearer abc123',
    'Content-Type: application/json'
];

$mh = curl_multi_init();
$handles = [];

foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_multi_add_handle($mh, $ch);
    $handles[] = $ch;
}

do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

foreach ($handles as $ch) {
    echo curl_multi_getcontent($ch) . "\n";
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

curl_multi_close($mh);

我们在多句柄中的所有请求上设置了相同的自定义标头。标头包括授权和内容类型。处理后,我们会妥善清理所有 cURL 资源。

性能比较:顺序 vs 并行

此示例比较了顺序和并行请求的执行。

performance.php
<?php

declare(strict_types=1);

$urls = array_fill(0, 5, "https://jsonplaceholder.typicode.com/posts/1");

// Sequential requests
$start = microtime(true);
foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_exec($ch);
    curl_close($ch);
}
$sequential = microtime(true) - $start;

// Parallel requests
$start = microtime(true);
$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;
}

do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

foreach ($handles as $ch) {
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

curl_multi_close($mh);
$parallel = microtime(true) - $start;

echo "Sequential: " . $sequential . " seconds\n";
echo "Parallel: " . $parallel . " seconds\n";

此代码演示了并行请求的性能优势。我们测量了两种方法的执行时间。并行执行完成后,多句柄会被妥善关闭。

最佳实践

来源

PHP curl_multi_close 文档

本教程涵盖了 PHP 的 curl_multi_close 函数,并通过实际示例展示了其在并行 HTTP 请求场景中的用法。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

所有 PHP cURL 教程列表。