<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// 本文档为学习和参考用途,介绍 PHP 中 curl_multi_add_handle 函数的基础使用方式。</span></span><span>
</span><span><span class="hljs-meta">?></span></span><span>
<hr>
</span><span><span class="hljs-comment"># curl_multi_add_handle 函数的基础用法详解,如何快速上手和理解它的工作原理?</span></span><span>
在使用 PHP 进行并发 HTTP 请求时,`curl_multi_add_handle` 是一个非常核心的函数。它配合 `curl_multi_init`、`curl_multi_exec` 等函数,可以实现并行地发送多个 cURL 请求,从而大大提高网络请求的效率。本文将详细介绍 `curl_multi_add_handle` 的基础用法,帮助你快速理解它的工作原理并动手实践。
</span><span><span class="hljs-comment">## 一、什么是 curl_multi_add_handle?</span></span><span>
`</span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>()` 是 PHP 中用于添加单个 cURL 请求(即 curl handle)到一个多 cURL 会话(multi handle)中的函数。它的作用是告诉 `curl_multi_exec`:“我这里有一个新的请求,请一并处理它”。
**函数签名:**
```php
</span><span><span class="hljs-keyword">bool</span></span><span> </span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>(CurlMultiHandle </span><span><span class="hljs-variable">$multi_handle</span></span><span>, CurlHandle </span><span><span class="hljs-variable">$ch</span></span><span>);
</span></span>
$multi_handle:通过 curl_multi_init() 创建的多请求句柄。
$ch:通过 curl_init() 创建的单个请求句柄。
返回值是布尔值,表示添加是否成功。
在默认的 cURL 请求中,每次请求都是同步阻塞的,也就是说,只有前一个请求完成后,才能执行下一个。这在需要请求多个接口或网站数据时非常低效。而 curl_multi 系列函数的引入,提供了一种非阻塞的并发处理方案。
下面是一个使用 curl_multi_add_handle 的完整示例,演示如何并行请求多个网页:
<span><span><span class="hljs-variable">$urls</span></span><span> = [
</span><span><span class="hljs-string">"https://www.example.com/"</span></span><span>,
</span><span><span class="hljs-string">"https://www.php.net/"</span></span><span>,
</span><span><span class="hljs-string">"https://www.wikipedia.org/"</span></span><span>
];
</span><span><span class="hljs-variable">$multiHandle</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_init</span></span><span>();
</span><span><span class="hljs-variable">$curlHandles</span></span><span> = [];
</span><span><span class="hljs-comment">// 初始化每个请求并添加到 multi handle 中</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$urls</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$url</span></span><span>) {
</span><span><span class="hljs-variable">$ch</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_init</span></span><span>();
</span><span><span class="hljs-title function_ invoke__">curl_setopt_array</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>, [
CURLOPT_URL => </span><span><span class="hljs-variable">$url</span></span><span>,
CURLOPT_RETURNTRANSFER => </span><span><span class="hljs-literal">true</span></span><span>,
CURLOPT_TIMEOUT => </span><span><span class="hljs-number">10</span></span><span>
]);
</span><span><span class="hljs-title function_ invoke__">curl_multi_add_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-variable">$curlHandles</span></span><span>[] = </span><span><span class="hljs-variable">$ch</span></span><span>;
}
</span><span><span class="hljs-comment">// 执行所有请求</span></span><span>
</span><span><span class="hljs-keyword">do</span></span><span> {
</span><span><span class="hljs-variable">$status</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_exec</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$active</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$active</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">curl_multi_select</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>); </span><span><span class="hljs-comment">// 等待 I/O</span></span><span>
}
} </span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-variable">$active</span></span><span> && </span><span><span class="hljs-variable">$status</span></span><span> == CURLM_OK);
</span><span><span class="hljs-comment">// 获取结果</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$curlHandles</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$ch</span></span><span>) {
</span><span><span class="hljs-variable">$content</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_multi_getcontent</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-variable">$info</span></span><span> = </span><span><span class="hljs-title function_ invoke__">curl_getinfo</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"URL: "</span></span><span> . </span><span><span class="hljs-variable">$info</span></span><span>[</span><span><span class="hljs-string">'url'</span></span><span>] . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"HTTP Code: "</span></span><span> . </span><span><span class="hljs-variable">$info</span></span><span>[</span><span><span class="hljs-string">'http_code'</span></span><span>] . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Content Length: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$content</span></span><span>) . </span><span><span class="hljs-string">"\n\n"</span></span><span>;
</span><span><span class="hljs-title function_ invoke__">curl_multi_remove_handle</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>, </span><span><span class="hljs-variable">$ch</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">curl_close</span></span><span>(</span><span><span class="hljs-variable">$ch</span></span><span>);
}
</span><span><span class="hljs-title function_ invoke__">curl_multi_close</span></span><span>(</span><span><span class="hljs-variable">$multiHandle</span></span><span>);
</span></span>
使用 curl_multi_init() 创建一个 multi handle。
对每个 URL 创建一个普通的 cURL handle,并设置好参数。
使用 curl_multi_add_handle() 把每个 handle 添加到 multi handle 中。
使用 curl_multi_exec() 启动所有请求的执行。
使用 curl_multi_select() 阻塞直到有活动连接。
处理完所有请求后,记得使用 curl_multi_remove_handle() 移除,并关闭所有句柄。
每个 handle 在添加到 multi handle 之前必须已经设置好所有必要的 CURLOPT_* 参数。
不要忘记清理资源:curl_multi_remove_handle() 和 curl_close()。
curl_multi_exec() 可能需要多次调用直到所有操作完成,这通常配合一个 do-while 循环。
curl_multi_select() 用于等待网络响应,避免空转 CPU。
curl_multi_add_handle 是构建高性能网络请求的基础,理解它的角色有助于你更深入掌握 PHP 中的异步处理能力。掌握了它,就能够实现并发爬虫、多接口聚合请求等高级功能,大幅提升你的 PHP 程序在 I/O 密集型场景下的效率。
通过多练习示例代码,你将能更熟练地运用这个函数,写出更高效、专业的 PHP 程序。
<span></span>