最稳妥直接用 http_build_query(),它自动处理嵌套、空值、编码和布尔值转换;手动拼接易出错,如 Array to string 警告、参数丢失、中文乱码、嵌套被忽略。

PHP中用 http_build_query() 最稳妥
直接用 http_build_query(),它专为这个场景设计,能自动处理键名嵌套、空值、特殊字符编码和布尔值转换。别自己拼接字符串或用 urlencode() 手动遍历——容易漏掉数组深层结构或编码不一致。
常见错误现象:Array to string conversion 警告(比如直接对数组用 echo),或者参数丢失(如 status=true 变成 status=1)、中文乱码(没编码)、嵌套数组被忽略(如 ['user'=>['name'=>'张']] 变成空)。
-
http_build_query()默认将true转为1,false转为0;如需保持true/false字符串,传第四个参数PHP_QUERY_RFC3986并配合手动替换(但一般不推荐,服务端通常按整型解析) - 值为
null的键默认被跳过;若需输出key=,得先用array_map()把null转成空字符串 - 嵌套一维数组(如
['a'=>[1,2]])会转成a[0]=1&a[1]=2;多维则继续展开,符合标准 URL 参数格式
遇到中文或特殊字符必须确认编码方式
http_build_query() 默认使用 UTF-8 编码,但如果你的原始数据是 GBK 或其他编码,结果会错乱。不要指望函数自动检测——它只认当前字符串字节流。
使用场景:老系统接口要求 GBK 参数、或从 $_POST 接收了 GBK 表单但没转码就直传。
立即学习“PHP免费学习笔记(深入)”;
- 先用
mb_convert_encoding($arr, 'UTF-8', 'GBK')统一转码再调用http_build_query() - 避免用
iconv('GBK', 'UTF-8//IGNORE', ...),//IGNORE可能静默丢字 - 如果后端明确要求不编码(极少见),得用
urldecode(http_build_query(...))——但大概率是设计缺陷,别妥协
自定义分隔符或键名格式时慎用 arg_separator.output
PHP 配置项 arg_separator.output 控制 http_build_query() 用什么符号分隔参数(默认 &)。改它会影响所有地方,包括 phpinfo() 输出、框架内部构造 URL 等,属于全局副作用。
性能影响不大,但兼容性风险高:某些 CDN 或代理会严格校验参数分隔符,非 & 可能被截断或拒绝。
- 真要换分隔符(例如用
;),应该手动替换:str_replace('&', ';', http_build_query($arr)) - 想把键名中的点号
.换成下划线_(如user.name→user_name),得先递归重键名,不能依赖配置 -
ini_set('arg_separator.output', ';')在 CLI 模式下可能无效,FPM 下也未必生效,别赌
curl POST 场景下别混淆 application/x-www-form-urlencoded 和 multipart/form-data
很多人以为 http_build_query() 结果直接塞进 curl_setopt($ch, CURLOPT_POSTFIELDS, $str) 就完事——这仅适用于 Content-Type: application/x-www-form-urlencoded。如果后端要求 multipart/form-data(比如带文件上传),这么传会导致参数全变成文件字段名或解析失败。
典型错误现象:接口返回 “missing required field”,但你确认字段都传了;或后端收到的值是完整 URL 编码字符串而非解码后的值。
- 纯数据提交(无文件):设
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)),并确保没手动设Content-Type头(cURL 会自动加) - 含文件上传:必须用
CURLOPT_POSTFIELDS传数组(如['name'=>'张', 'avatar'=>new CURLFile('/tmp/a.jpg')]),此时http_build_query()完全不适用 - 不确定后端类型时,先看文档或抓包对比正常请求的
Content-Type和 body 格式
最易被忽略的是嵌套空数组的处理:['filters'=>['status'=>[], 'type'=>'active']] 传出去会变成 filters[status]=&filters[type]=active,有些后端框架会把空数组当 null 或直接跳过。需要提前过滤掉空数组,或根据接口约定转成 filters[status]=null 再 urlencode。



















