PHP实现异步请求的四种方法

PHP教程 2025-07-31

目录

  • 使用curl_multi
  • 使用 pthreads
  • 使用Guzzle库
  • 使用Swoole扩展
  • 总结

PHP中的cURL可用于发起 HTTP 请求,通常同步地等待服务器响应。如果你想要实现异步操作,即 PHP 程序继续执行而无需等待 cURL 请求完成,你可以考虑以下几种方式:

使用curl_multi

cURL 提供了设置 curl_multi和 curl_multi_exec来同时处理多个请求,这种方式下你需要编写回调函数来处理每个请求的结果。

$urls = [
    'http://exam*p*le.c*om/api/endpoint1',
    'http://*ex*ample.c*om/api/endpoint2',
    // ...更多URLs
];
 
$multiHandle = curl_multi_init();
 
foreach ($urls as $url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_multi_add_handle($multiHandle, $ch);
}
 
$running = null;
do {
    usleep(10000); // 可选:防止CPU全速运行
    curl_multi_exec($multiHandle, $running);
} while ($running  0);
 
foreach ($urls as $url) {
    $ch = curl_multi_getcontent($ch);
    // 处理结果
    curl_multi_remove_handle($multiHandle, $ch);
}
 
curl_multi_close($multiHandle);

使用 pthreads

虽然 PHP 自身并不是原生支持多线程的语言,但是可以借助 pthreads 扩展创建并管理线程,让 cURL 在另一个线程里运行。

?php
require 'vendor/autoload.php';
$promise = new ReactPromisePromise(function ($resolve, $reject) {
    // 创建 cURL 操作
    $ch = curl_init();
    // 设置请求选项...
    curl_setopt($ch, CURLOPT_URL, 'http://ex*ample.c**om');
    // 创建一个新的 React 异步客户端
    $client = new ReactCurlAdapterCurl();
    // 使用 React 异步库发起请求
    $response = $client-enqueue($ch);
    // 当请求完成后,调用 resolve 或 reject 函数
    $response-then(
        function ($result) use ($resolve) { $resolve(json_decode($result)); },
        function ($error) use ($reject) { $reject($error); }
    );
});
// 同时,主线程继续执行其他任务
$promise-wait(); // 当 cURL 完成后,此处阻塞
?

使用Guzzle库

Guzzle是一个功能强大的HTTP客户端库,可以用于发送异步HTTP请求。它提供了方便的接口和功能,使得发送异步请求变得更加简单。以下是一个使用Guzzle库发送异步请求的示例代码:

$client = new GuzzleHttpClient();
$promises = [
    'api1' = $client-getAsync('http://ex*amp*l*e.com/api1'),
    'api2' = $client-getAsync('http://*example.c**om/api2'),
];
$results = GuzzleHttpPromiseUtils::settle($promises)-wait();
$response1 = $results['api1']['value']-getBody()-getContents();
$response2 = $results['api2']['value']-getBody()-getContents();
// 处理响应数据
// …