thinkphp 6 的 input() 默认不扁平化嵌套参数,保留原始结构(如 user[name] → ['user' => ['name' => 'xxx']]),需手动用 request::param() 配合递归函数实现可控扁平化。

ThinkPHP 6 的 input() 默认不扁平化嵌套参数
ThinkPHP 6 的 input() 函数默认保留原始请求结构,比如 POST 提交 user[name] 和 user[age],会得到 ['user' => ['name' => 'xxx', 'age' => 18]]。这不是 bug,是设计使然 —— 它原样映射了 PHP 的 $_POST 解析逻辑。但多数业务层(如验证、入库、日志记录)更习惯一维键名,比如 user_name 或直接 name。
常见错误现象:
• 验证规则写 'name' => 'require',但实际字段在 user.name 里,校验永远不触发
• 直接用 input('name') 取不到值,却没意识到它藏在嵌套数组里
• 用 input('user.') 手动展开,但漏掉多层(如 data.list[0].id)或动态 key
- 真正需要扁平化的场景:统一表单提交、第三方回调解析、与非 ThinkPHP 系统对接时的参数对齐
- 不要在所有接口无差别扁平化 —— RESTful 资源嵌套(如
PUT /users/1带{ "profile": { "city": "sh" } })应保持语义结构 - 性能影响极小,但要注意:扁平后若出现同名 key(如
a[b]和a_b),后者会覆盖前者,需约定命名避让
用 think\facade\Request::param() + 自定义递归函数最可控
Request::param() 比 input() 更底层,返回原始解析后的数组,且不走自动类型转换,适合作为扁平化起点。手动写个递归函数比依赖第三方扩展更轻量、更易调试。
实操建议:
- 把函数放在
app/common/Helper.php或app/Support/ArrayHelper.php,避免污染控制器 - 用下划线连接层级(
user_profile_city),不用点号(user.profile.city),避免和验证器字段语法冲突 - 跳过数值索引数组(如
[0] => x, [1] => y),只处理字符串 key,防止把列表误展平成list_0/list_1 - 对空数组、null 值保留原样,不生成冗余键(即
['a' => []]不产出a_这种空 key)
示例片段:
function flattenArray(array $array, string $prefix = ''): array
{
$result = [];
foreach ($array as $key => $value) {
if (is_array($value) && is_string($key)) {
$result += flattenArray($value, $prefix . $key . '_');
} elseif (is_string($key)) {
$result[$prefix . $key] = $value;
}
}
return $result;
}
// 在控制器中:
use think\facade\Request;
$data = flattenArray(Request::param()); // 得到一维数组
注意 input() 的第三个参数会影响扁平化结果
input() 第三个参数是 $filter,控制是否开启全局过滤(如 trim、htmlspecialchars)。如果开启,而你又在扁平化前调用了 input(),会导致部分值已被处理,后续再扁平就可能出错(比如 JSON 字段被提前 decode 成数组,又进递归函数)。
容易踩的坑:
- 别混用:
input('user.') → 得到子数组 → 再 flatten,这种写法不可靠,因为input('user.')本身不保证返回结构一致(遇到空值、缺失键时行为不同) - 如果必须用
input(),务必关掉过滤:input('', '', false),再传给扁平函数 - 验证器里别指望
validate(['name' => 'require'])能自动识别扁平后字段 —— 验证规则得和你最终传入的数据结构完全匹配 - GET 查询串里的嵌套(
?filter[status]=1&filter[type]=2)同样适用该扁平逻辑,无需额外分支
复杂嵌套(如 JSON body)需先 json_decode 再扁平
当接口接收的是 raw JSON(Content-Type: application/json),Request::param() 默认拿不到 —— 它只处理 application/x-www-form-urlencoded 和 multipart/form-data。此时必须显式读取原始输入流。
关键点:
- 用
Request::getContent()获取原始字符串,再json_decode($content, true) - 检查
json_last_error(),避免无效 JSON 导致扁平函数崩溃 - JSON 中的数字 key(如
{"1": "a", "2": "b"})会被 PHP 自动转成整型索引,你的扁平函数要能跳过这类 key,否则产出1、2这种非法字段名 - 别在中间件里全局做这一步 —— 不是所有接口都接受 JSON,也并非所有 JSON 都需要扁平,按需在具体控制器中处理更安全
事情说清了就结束。扁平本身不难,难的是判断「哪里真需要扁」和「扁完谁来消费它」—— 多数时候,问题不在怎么扁,而在验证器、模型、日志三者之间对字段名的约定是否一致。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











