<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>