swoole_hook_curl 使 curl_init() 返回 swoole\curl\handler 对象,导致阿里云 oss sdk 等依赖原生 resource/curlhandle 的组件报错;swoole_hook_native_curl 自 v4.6.0 起保留原生类型并协程化 curl_exec/curl_multi,但需编译时启用 --enable-swoole-curl 且运行时显式开启。

SWOOLE_HOOK_CURL 会让 curl_exec 变成 object 类型
启用 SWOOLE_HOOK_CURL 后,curl_init() 返回的不再是 PHP 原生的 resource(PHP 7.x)或 CurlHandle(PHP 8+),而是一个 Swoole\Curl\Handler 对象。这会导致很多依赖原生 cURL 类型判断的 SDK 直接报错:
PHP Warning: curl_multi_add_handle() expects parameter 2 to be resource, object givenPHP Notice: Object of class Swoole\Curl\Handler could not be converted to int
典型受害者包括阿里云 OSS SDK、部分老版本 Guzzle(未适配 PHP 8+ 的 CurlHandle)、自定义封装的 multi 批量请求逻辑。
SWOOLE_HOOK_NATIVE_CURL 保持原生类型不变
从 Swoole v4.6.0 起,SWOOLE_HOOK_NATIVE_CURL 成为更安全的选择:它不替换 curl_init() 的返回值,仍返回标准 CurlHandle(PHP 8+)或 resource(PHP 7.x),同时让 curl_exec()、curl_multi_exec() 等调用自动协程化。
关键前提:
- 编译 Swoole 时必须加
--enable-swoole-curl参数(pecl 安装默认不开启) - 运行时需显式启用:
Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL) - 验证是否生效:
php --ri swoole | grep "curl-native"应输出curl-native => enabled
为什么不能只用 SWOOLE_HOOK_ALL?
SWOOLE_HOOK_ALL 默认不包含 cURL 支持——这是设计上的明确分离。cURL 底层走 libcurl,和 PHP 流层(fsockopen、stream_socket_client)完全无关。所以即使开了 SWOOLE_HOOK_ALL,curl_exec() 依然阻塞。
正确组合是:
- 用 Guzzle / file_get_contents('http://') → 开
SWOOLE_HOOK_TCP(它覆盖 stream 层) - 用原生
curl_*()系列函数 → 必须单独加SWOOLE_HOOK_NATIVE_CURL - 生产环境推荐:
SWOOLE_HOOK_ALL | SWOOLE_HOOK_NATIVE_CURL
curl_multi 在协程中能直接用吗?
可以,但仅限 SWOOLE_HOOK_NATIVE_CURL。v4.6.5 起已完整支持 curl_multi_init()、curl_multi_add_handle()、curl_multi_exec() 和 curl_multi_select() 的协程调度。
注意点:
- 不要在
curl_multi_exec()循环里手动usleep()或sleep(),会破坏协程调度 - 每个
curl_init()实例仍需独立设置CURLOPT_RETURNTRANSFER等选项 - Guzzle 无需改任何代码,只要底层用了
curl_multi且启用了SWOOLE_HOOK_NATIVE_CURL,就自动协程化
最易被忽略的是编译开关——没开 --enable-swoole-curl,哪怕代码里写了 SWOOLE_HOOK_NATIVE_CURL 也完全不生效。










