在 PHP 中使用 cURL 进行网络请求是一种非常常见的做法,尤其是在需要和外部 API 通信时。然而,如果你没有正确关闭使用过的 cURL 句柄,可能会导致内存泄漏或资源浪费等问题。本文将围绕如何正确使用 curl_close 函数,确保所有打开的句柄都被正确关闭进行详细讲解,尤其是在进行并发请求或循环操作时的注意事项。
在最基本的使用场景下,关闭 cURL 句柄相对简单:
$ch = curl_init('https://gitbox.net/api/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
这段代码在请求完成后立即使用 curl_close 关闭了句柄,是推荐的做法。
当你需要发送多个请求时,通常会使用循环,这时候很容易遗漏关闭句柄:
$urls = [
'https://gitbox.net/api/user/1',
'https://gitbox.net/api/user/2',
'https://gitbox.net/api/user/3',
];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// 如果忘记 curl_close($ch),每次迭代都会留下一份未释放资源
}
在这种情况下,必须在每次迭代后手动关闭句柄:
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch); // 确保关闭句柄
}
如果你使用的是 curl_multi_init 实现并发请求,那么关闭句柄的顺序需要注意:
$multiHandle = curl_multi_init();
$curlHandles = [];
$urls = [
'https://gitbox.net/api/task/1',
'https://gitbox.net/api/task/2',
'https://gitbox.net/api/task/3',
];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$curlHandles[] = $ch;
}
// 执行并发请求
$running = null;
do {
curl_multi_exec($multiHandle, $running);
curl_multi_select($multiHandle);
} while ($running > 0);
// 移除和关闭所有句柄
foreach ($curlHandles as $ch) {
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch); // 这里是关闭的关键步骤
}
curl_multi_close($multiHandle);
注意,这里除了 curl_close($ch),还必须先调用 curl_multi_remove_handle 移除句柄,才能安全地关闭。
为了避免手动忘记关闭句柄,可以将请求过程封装在函数中,确保在函数结束时关闭资源:
function fetchUrl($url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch); // 保证资源在函数内部关闭
return $response;
}
$data = fetchUrl('https://gitbox.net/api/config');
始终调用 curl_close() 关闭句柄,即使请求失败。
在循环中或使用多句柄并发时,不要遗漏 curl_close。
如果使用 curl_multi_*,确保先用 curl_multi_remove_handle 再用 curl_close。
尽可能将请求逻辑封装为函数,确保清理工作在内部完成,减少遗漏的风险。
正确释放资源不仅能提高脚本的效率和健壮性,还能避免服务器上的资源泄漏风险。在多线程或大批量请求的场景中,尤其重要。通过良好的编码习惯和结构设计,可以轻松确保每一个 cURL 句柄都被正确关闭。