PHP多维数组如何保留原有键 仅对数字键项用array_values()解决json_encode问题
解决方案
核心问题说明
PHP 内置 json_encode() 的编码规则会直接决定输出格式:
- 只有当数组的所有键为整数,且是从0开始连续递增的序列时,才会被编码为标准JSON数组格式
[] - 只要数组存在非整数键,或是整数键不连续(比如从1开始、存在索引间隔),就会被强制编码为JSON对象格式
{}
你遇到的 supply 子数组使用非连续的数字键 1 作为索引,正是触发了上述规则,导致最终JSON输出不符合预期;而直接对全量数组调用 array_values() 会把顶层所有字符串键(比如 @context、@type)替换为数字索引,彻底破坏原有语义结构。
实现思路
采用递归遍历的方式逐层处理嵌套数组,匹配你的核心需求:
- 逐层级判断数组属性:如果当前层是纯数字键构成的数组,就对这层调用
array_values(),重排为从0开始的连续索引 - 如果当前层是字符串键构成的关联数组,完整保留原有键值对结构,不做任何键替换
- 无论处理到哪一层,都会继续深入遍历节点下的数组类型值,重复上述判断流程,直到覆盖所有嵌套层级
可直接使用的工具函数
/** * 递归规范数字索引数组,保留字符串键关联结构 */ function formatNestedArray(array $array): array { // 判断当前层级是否为纯数字键数组 $allNumericKeys = true; foreach (array_keys($array) as $key) { if (!is_int($key) && !ctype_digit((string)$key)) { $allNumericKeys = false; break; } } // 对纯数字键的层级重排连续索引 if ($allNumericKeys) { $array = array_values($array); } // 递归处理所有子数组节点 foreach ($array as $key => $value) { if (is_array($value)) { $array[$key] = formatNestedArray($value); } } return $array; }
针对你提供的数组结构的执行效果
- 顶层数组全为字符串键(
@context、@type、name、supply、step),会被100%保留原有键名,不会出现全局调用array_values()导致的键值替换问题 - 进入
supply对应的子数组,检测到其为纯数字键结构,会自动调用array_values()把索引从1重排为0,满足json_encode()输出标准数组的要求 - 进入
step对应的子数组,检测到其为纯数字键结构,重排后依然保持从0开始的连续索引,不产生结构变化 - 所有嵌套在字符串键下的子数组(比如
HowToSupply、HowToStep、ImageObject节点),因为全是字符串键结构,会被完整保留原有语义,不会被修改。
轻量替代方案
如果数组嵌套层级较浅,不需要写通用递归函数,也可以手动对存在非连续数字键的节点单独处理:
- 不修改顶层数组的字符串键
- 仅对存在非连续数字键的
supply节点单独调用array_values() - 处理完成后直接调用
json_encode()即可输出符合预期的格式,避免递归带来的额外性能开销。
内容的提问来源于stack exchange,提问作者ralphjsmit
相关产品推荐
相关产品推荐

