curl_copy_handle() 函数用于复制一个cURL句柄及其所有选项。复制后的句柄是独立的,可以单独设置选项和执行,同时保留了原始句柄的配置。
curl_copy_handle ( CurlHandle $handle ) : CurlHandle|false
| 参数 | 描述 |
|---|---|
| handle | 由 curl_init() 返回的 cURL 句柄。 |
返回复制后的cURL句柄,失败时返回 false。
// 创建原始cURL句柄
$originalHandle = curl_init();
// 设置一些选项
curl_setopt_array($originalHandle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_USERAGENT => 'MyCustomAgent/1.0',
CURLOPT_FOLLOWLOCATION => true
]);
// 复制句柄
$copiedHandle = curl_copy_handle($originalHandle);
// 现在可以分别设置URL并执行
curl_setopt($originalHandle, CURLOPT_URL, 'https://httpbin.org/get');
curl_setopt($copiedHandle, CURLOPT_URL, 'https://httpbin.org/post');
// 设置copiedHandle为POST请求
curl_setopt($copiedHandle, CURLOPT_POST, true);
curl_setopt($copiedHandle, CURLOPT_POSTFIELDS, ['key' => 'value']);
// 执行两个请求
$response1 = curl_exec($originalHandle);
$response2 = curl_exec($copiedHandle);
echo "原始句柄HTTP状态码: " . curl_getinfo($originalHandle, CURLINFO_HTTP_CODE) . "\n";
echo "复制句柄HTTP状态码: " . curl_getinfo($copiedHandle, CURLINFO_HTTP_CODE) . "\n";
// 清理资源
curl_close($originalHandle);
curl_close($copiedHandle);
// 创建一个请求模板
function createRequestTemplate() {
$template = curl_init();
// 设置公共选项
curl_setopt_array($template, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_USERAGENT => 'MyApp/1.0',
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Accept-Language: en-US,en;q=0.9',
'Cache-Control: no-cache'
]
]);
return $template;
}
// 使用模板创建多个请求
$template = createRequestTemplate();
// 复制模板创建不同的请求
$request1 = curl_copy_handle($template);
$request2 = curl_copy_handle($template);
$request3 = curl_copy_handle($template);
// 为每个请求设置不同的URL
curl_setopt($request1, CURLOPT_URL, 'https://api.example.com/users');
curl_setopt($request2, CURLOPT_URL, 'https://api.example.com/products');
curl_setopt($request3, CURLOPT_URL, 'https://api.example.com/orders');
// 可以为某些请求添加特定选项
curl_setopt($request3, CURLOPT_POST, true);
curl_setopt($request3, CURLOPT_POSTFIELDS, json_encode(['status' => 'active']));
curl_setopt($request3, CURLOPT_HTTPHEADER, array_merge(
['Content-Type: application/json'],
curl_getinfo($request3, CURLINFO_HTTPHEADER)
));
// 执行所有请求
$responses = [
'users' => curl_exec($request1),
'products' => curl_exec($request2),
'orders' => curl_exec($request3)
];
// 获取状态码
foreach (['request1' => $request1, 'request2' => $request2, 'request3' => $request3] as $name => $handle) {
echo "{$name} HTTP状态码: " . curl_getinfo($handle, CURLINFO_HTTP_CODE) . "\n";
}
// 清理资源
curl_close($template);
curl_close($request1);
curl_close($request2);
curl_close($request3);
function batchProcessUrls($urls, $commonOptions = []) {
// 创建基础句柄
$baseHandle = curl_init();
// 设置基础选项
$defaultOptions = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'BatchProcessor/1.0'
];
curl_setopt_array($baseHandle, array_merge($defaultOptions, $commonOptions));
$handles = [];
$multiHandle = curl_multi_init();
// 为每个URL创建句柄
foreach ($urls as $index => $url) {
// 复制基础句柄
$ch = curl_copy_handle($baseHandle);
// 设置URL
curl_setopt($ch, CURLOPT_URL, $url);
// 添加到多句柄
curl_multi_add_handle($multiHandle, $ch);
$handles[$index] = $ch;
}
// 执行并发请求
$active = null;
do {
$mrc = curl_multi_exec($multiHandle, $active);
} while ($active && $mrc == CURLM_OK);
// 收集结果
$results = [];
foreach ($handles as $index => $ch) {
$results[$index] = [
'url' => $urls[$index],
'content' => curl_multi_getcontent($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'error' => curl_error($ch)
];
// 清理
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
// 清理基础句柄和多句柄
curl_close($baseHandle);
curl_multi_close($multiHandle);
return $results;
}
// 使用示例
$urls = [
'https://httpbin.org/get',
'https://httpbin.org/ip',
'https://httpbin.org/user-agent',
'https://httpbin.org/headers'
];
$results = batchProcessUrls($urls);
foreach ($results as $index => $result) {
echo "请求 {$index} ({$result['url']}): HTTP {$result['http_code']}\n";
if ($result['error']) {
echo " 错误: {$result['error']}\n";
}
}
class ApiClient {
private $baseHandle;
private $baseUrl;
public function __construct($baseUrl, $defaultHeaders = []) {
$this->baseUrl = rtrim($baseUrl, '/');
$this->baseHandle = curl_init();
// 设置基础配置
curl_setopt_array($this->baseHandle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5
]);
if (!empty($defaultHeaders)) {
curl_setopt($this->baseHandle, CURLOPT_HTTPHEADER, $defaultHeaders);
}
}
public function request($method, $endpoint, $data = null, $headers = []) {
// 复制基础句柄
$ch = curl_copy_handle($this->baseHandle);
// 构建完整URL
$url = $this->baseUrl . '/' . ltrim($endpoint, '/');
curl_setopt($ch, CURLOPT_URL, $url);
// 设置HTTP方法
switch (strtoupper($method)) {
case 'POST':
curl_setopt($ch, CURLOPT_POST, true);
break;
case 'PUT':
case 'PATCH':
case 'DELETE':
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
break;
default:
curl_setopt($ch, CURLOPT_HTTPGET, true);
}
// 设置数据
if ($data !== null) {
if (is_array($data)) {
$data = http_build_query($data);
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
}
if (is_string($data)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
}
// 设置自定义头
if (!empty($headers)) {
$headerArray = [];
foreach ($headers as $key => $value) {
$headerArray[] = "{$key}: {$value}";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
}
// 执行请求
$response = curl_exec($ch);
$result = [
'success' => $response !== false,
'response' => $response,
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'error' => curl_error($ch),
'info' => curl_getinfo($ch)
];
curl_close($ch);
return $result;
}
public function get($endpoint, $headers = []) {
return $this->request('GET', $endpoint, null, $headers);
}
public function post($endpoint, $data, $headers = []) {
return $this->request('POST', $endpoint, $data, $headers);
}
public function put($endpoint, $data, $headers = []) {
return $this->request('PUT', $endpoint, $data, $headers);
}
public function __destruct() {
if ($this->baseHandle) {
curl_close($this->baseHandle);
}
}
}
// 使用示例
$client = new ApiClient('https://httpbin.org', [
'Accept' => 'application/json',
'X-API-Key' => 'your-api-key-here'
]);
// 发送GET请求
$result = $client->get('get');
echo "GET请求: HTTP {$result['http_code']}\n";
// 发送POST请求
$result = $client->post('post', ['name' => 'John', 'age' => 30], [
'Content-Type' => 'application/json'
]);
echo "POST请求: HTTP {$result['http_code']}\n";
// 发送PUT请求
$result = $client->put('put', json_encode(['status' => 'updated']), [
'Content-Type' => 'application/json'
]);
echo "PUT请求: HTTP {$result['http_code']}\n";
// 测试复制句柄的性能
function testCopyHandle($iterations) {
// 创建基础句柄
$baseHandle = curl_init();
curl_setopt_array($baseHandle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'TestAgent',
CURLOPT_HTTPHEADER => ['Accept: application/json']
]);
$startTime = microtime(true);
$memoryStart = memory_get_usage();
$handles = [];
for ($i = 0; $i < $iterations; $i++) {
$handles[] = curl_copy_handle($baseHandle);
}
$endTime = microtime(true);
$memoryEnd = memory_get_usage();
// 清理
foreach ($handles as $handle) {
curl_close($handle);
}
curl_close($baseHandle);
return [
'time' => $endTime - $startTime,
'memory' => $memoryEnd - $memoryStart
];
}
// 测试新建句柄的性能
function testNewHandle($iterations) {
$startTime = microtime(true);
$memoryStart = memory_get_usage();
$handles = [];
for ($i = 0; $i < $iterations; $i++) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'TestAgent',
CURLOPT_HTTPHEADER => ['Accept: application/json']
]);
$handles[] = $ch;
}
$endTime = microtime(true);
$memoryEnd = memory_get_usage();
// 清理
foreach ($handles as $handle) {
curl_close($handle);
}
return [
'time' => $endTime - $startTime,
'memory' => $memoryEnd - $memoryStart
];
}
// 运行测试
$iterations = 100;
$copyResult = testCopyHandle($iterations);
$newResult = testNewHandle($iterations);
echo "性能对比测试 ({$iterations} 次迭代):\n";
echo "================================\n";
echo "复制句柄:\n";
echo " 时间: " . round($copyResult['time'] * 1000, 2) . " 毫秒\n";
echo " 内存: " . round($copyResult['memory'] / 1024, 2) . " KB\n";
echo "\n新建句柄:\n";
echo " 时间: " . round($newResult['time'] * 1000, 2) . " 毫秒\n";
echo " 内存: " . round($newResult['memory'] / 1024, 2) . " KB\n";
echo "\n性能提升:\n";
echo " 时间节省: " . round((1 - $copyResult['time'] / $newResult['time']) * 100, 2) . "%\n";
echo " 内存节省: " . round((1 - $copyResult['memory'] / $newResult['memory']) * 100, 2) . "%\n";
| 方面 | curl_copy_handle | curl_reset |
|---|---|---|
| 作用 | 创建新的独立句柄副本 | 重置现有句柄的所有选项 |
| 返回值 | 新的cURL句柄 | void |
| 内存使用 | 创建新资源,使用更多内存 | 重用现有资源,内存效率高 |
| 使用场景 | 需要多个相似但独立的连接 | 复用同一个句柄进行不同请求 |
| 并发支持 | 适合并发请求 | 适合顺序请求 |
curl_close() 来释放。不要忘记清理所有创建的句柄。
A: 是的,curl_copy_handle() 会复制源句柄的所有选项设置,包括URL、HTTP方法、头信息、超时设置等。
A: 复制后的句柄是独立的资源,对复制句柄的修改不会影响原始句柄,反之亦然。它们可以独立使用和配置。
A: 当需要创建多个配置相似的cURL句柄时,使用 curl_copy_handle() 可以提高性能并简化代码。特别是当基础配置复杂时,复制可以避免重复设置选项。
A: curl_copy_handle() 通常比创建新句柄并设置所有选项要快,特别是当配置复杂时。但在只需要少量简单请求时,直接创建新句柄可能更简单。