PHP 8.1 中 array_is_list() 并未改变键名,而是让 json_encode() 更精准判断数组是否为连续整数索引列表,从而决定输出 JSON 数组 [] 还是对象 {};非列表或键不连续时自动转为字符串键对象,符合 JSON 规范。

PHP 8.1 中数组序列化为 JSON 后键名类型“看似改变”,其实不是键名真的变了,而是 PHP 数组和 JSON 的语义模型根本不同——JSON 本身不支持“整数键”或“混合键”的概念,它只有两种结构:对象(object)和数组(array),而它们的键规则是硬性的。
关键区别:PHP 数组键 vs JSON 键
PHP 数组允许:
• 整数键(如 [0 => 'a', 2 => 'c'])
• 字符串键(如 ['name' => 'Alice'])
• 混合键(如 [0 => 'first', 'id' => 123])
• 键顺序被保留,且整数键可能自动重排(例如 unset 后再添加)
JSON 要求:
• 对象({})的键必须是字符串,且无序
• 数组([])没有“键”,只有连续、从 0 开始的索引;它不接受字符串键或跳跃索引
所以当你用 json_encode() 处理一个 PHP 数组时,PHP 不是“转换键类型”,而是根据数组是否满足“列表(list)”定义,决定输出 [] 还是 {}:
- 如果数组是 list(即键为
0,1,2,...连续整数),json_encode()输出 JSON 数组[] - 只要有一个非数字键(如
'name')或键不连续(如[0=>'a', 2=>'c']),就输出 JSON 对象{},此时所有键会被强制转为字符串
PHP 8.1 新增 array_is_list() 的作用
这个函数正是为了解决“到底算不算数组”的模糊判断。它严格检查:
• 键是否全为整数
• 是否从 0 开始
• 是否连续递增(无空缺)
例如:
-
array_is_list([0=>'a', 1=>'b'])→true→json_encode()输出["a","b"] -
array_is_list([1=>'a', 2=>'b'])→false→ 输出{"1":"a","2":"b"} -
array_is_list(['name'=>'Alice'])→false→ 输出{"name":"Alice"}
这解释了为什么你看到“键名变了”:不是编码出错,而是 PHP 主动按 JSON 规范做了结构适配。
立即学习“PHP免费学习笔记(深入)”;
如何控制输出结构?
如果你明确希望某个关联数组始终输出为 JSON 对象(哪怕键是数字),可用 JSON_FORCE_OBJECT:
-
json_encode([0=>'a', 1=>'b'], JSON_FORCE_OBJECT)→{"0":"a","1":"b"} - 反之,若想让带字符串键的数组也尽量“假装”成列表(不推荐,会丢失键名),需先重索引:
array_values($arr)
注意:JSON_FORCE_OBJECT 对对象无效,只影响数组。
解码后无法还原原始键类型
json_decode() 默认返回 stdClass 对象,所有键都是字符串;即使你传 true 得到关联数组,它也是纯 PHP 数组,但无法区分当初是 list 还是 object——因为 JSON 本身已抹去该信息。
比如:
• json_encode([0=>'x']) → ["x"]
• json_encode(['0'=>'x']) → {"0":"x"}
两者解码后都可能是 ['0'=>'x'] 或 (object)['0'=>'x'],原始语义已不可逆。



















