[]是空索引数组的标准JSON表现,因json_encode仅依据键名类型(连续数字键)判定输出为[];若需输出{},可用JSON_FORCE_OBJECT标志或new ArrayObject()。
![php json_encode空数组为什么变成[]](https://img.php.cn/upload/article/001/431/639/178815608484550.jpeg)
PHP 中 json_encode([]) 输出 [],是因为这个空数组是索引数组——键名是连续的整数(从 0 开始),哪怕它一个元素都没有。
json_encode 不看内容是否为空,只看数组的“结构类型”:
- 键全是连续数字(如
0,1,2...或空数组[])→ 编码为 JSON 数组[] - 只要有一个字符串键(如
['a' => 1]、[1 => 'x', 'name' => 'y'])→ 编码为 JSON 对象{}
所以 [] 是完全合法且符合预期的行为,它代表一个空的 JSON 数组,不是 bug,而是设计逻辑。
空数组输出 [] 的本质原因
- PHP 没有独立的“空索引数组”和“空关联数组”类型,但
json_encode会通过键名推断语义 -
[]在 PHP 中默认创建的是索引数组(等价于array()) -
json_encode检测到该数组没有非数字键、也没有中断的数字键 → 判定为“纯索引型” → 输出[]
为什么有时你看到的是 {} 而不是 []?
常见误判来源:
立即学习“PHP免费学习笔记(深入)”;
-
$arr = ['name' => 'tom'];→ 有字符串键 →{"name":"tom"} -
$arr = [1 => 'a', 3 => 'b'];→ 键不连续(缺 2)→{"1":"a","3":"b"} -
$arr = [];但之前被赋过字符串键:$arr = []; $arr['id'] = 123; // 此时已变成关联数组 unset($arr['id']); // 键没了,但内部仍保留“关联”属性? // 实际上:unset 后 $arr === [],仍是索引数组 → 还是输出 []
✅ 真正影响结果的只有当前键名类型,不是历史操作。
如何让空数组也输出 {}?
用 JSON_FORCE_OBJECT 标志:
json_encode([]); // "[]"
json_encode([], JSON_FORCE_OBJECT); // "{}"⚠️ 注意:这个标志会影响整个结构,包括子数组:
$data = [
'items' => ['a', 'b'],
'meta' => []
];
echo json_encode($data, JSON_FORCE_OBJECT);
// 输出:{"items":{"0":"a","1":"b"},"meta":{}}
// ❌ 'items' 也被对象化了,不再是数组更精准的做法是只对特定字段强制对象化,比如:
$data['meta'] = new \ArrayObject(); // 空 ArrayObject 编码为 {}
echo json_encode($data); // {"items":["a","b"],"meta":{}}前端或 App 接口为什么在意 [] 还是 {}?
- JavaScript:
Array.isArray([]) === true,Array.isArray({}) === false - Java / Swift / Kotlin:JSON 解析器依赖字段类型声明,
"list": []和"list": {}可能导致反序列化失败或 crash - 所以接口契约要求某字段始终是 object 类型时,空值也应返回
{},不能是[]
总结关键点
-
[]是空索引数组的标准 JSON 表现,完全正确 - 想输出
{},可用JSON_FORCE_OBJECT(全局)或new ArrayObject()(局部) - 判断依据永远是当前数组键的类型,不是内容、不是历史、不是变量名
- 接口设计阶段就该明确每个字段的 JSON 类型(array/object),并在 PHP 层主动保障一致性



















