cURL is one of the most common tools when using PHP for network requests. Many developers will close the resource according to the standard process after completing the request, that is, call curl_close($ch) . However, in some scenarios with high concurrency or high performance requirements, we will encounter a secret problem: after calling curl_close , there is an unreasonable delay in the execution of the PHP script.
This delay usually occurs in a context of a long connection (Keep-Alive) or a specific server configuration. Although it seems that the request has been completed, curl_close may actually be waiting for the release process of the underlying connection, thus blocking the continued execution of the script.
Let's take a look at a simple example:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/data");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo "Request complete";
In most cases, this code can be executed quickly. But in some server environments (especially when the target server supports HTTP/2 or connection multiplexing), curl_close can be blocked for hundreds of milliseconds or even longer.
curl_close does not simply free memory, it may also wait for the underlying TCP connection to be closed or freed resources, especially when HTTP Keep-Alive is enabled. This behavior is more obvious when using newer versions of the libcurl library, or when communicating with specific servers (such as Nginx + Keep-Alive).
In addition, when curl_exec returns data large or the connection is not fully read, curl_close may attempt to clean up the remaining data in the background, which further increases execution time.
You can force close the connection by setting CURLOPT_FORBID_REUSE to avoid the delay caused by connection reuse:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.gitbox.net/data");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // Disable connection reuse
$response = curl_exec($ch);
curl_close($ch);
This method will sacrifice some performance (because a new connection is created for every request), but it can effectively avoid curl_close blocking problems.
If you only need to make simple GET requests and are very concerned about performance, consider using fsocckopen to manually construct the requests, thus completely bypassing the resource management logic of cURL.
If you are using asynchronous frameworks such as Swoole and ReactPHP, you can encapsulate curl as an asynchronous task and perform release operations in the background to avoid blocking the main thread.
For a large number of requests, you can use the curl_multi_* interface to uniformly manage connections, avoiding frequent creation and destruction of handles, thereby reducing the overhead of curl_close . But this is an advanced usage and is suitable for building SDKs or underlying libraries.
Although curl_close seems to be just an operation to close the handle, it can become a performance bottleneck in some scenarios. By setting the curl option reasonably or selecting other network request methods according to actual needs, unnecessary delays caused by curl_close can be effectively avoided. In performance-sensitive PHP projects, focusing on these details often leads to a smoother user experience and higher system throughput.