关于 JSON 解码为 PHP 数组后索引被重排的问题

现在我需要解码一个地区缓存文件,该文件以 json 的形式存储地区信息,键为地区 ID ,值为地区名称。
PHP 的 json_decode() 方法可以解码为数组或对象。
解码为对象时,没碰到问题(使用 laravel 的 dd() 方法获取,下同)。

{#1961
  +"province_list": {#1960
    +"110000": "北京市"
    +"120000": "天津市"
    +"130000": "河北省"
    +"140000": "山西省"
    +"150000": "内蒙古自治区"
    +"210000": "辽宁省"
    +"220000": "吉林省"
    // 以下省略 20 多个地区
  }
  +"city_list": {#1962
    +"110100": "市辖区"
    +"120100": "市辖区"
    +"130100": "石家庄市"
    +"130200": "唐山市"
    +"130300": "秦皇岛市"
    +"130400": "邯郸市"
    +"130500": "邢台市"
    // 以下省略 300 多个地区
  }
  +"county_list": {#1963
    +"110101": "东城区"
    +"110102": "西城区"
    +"110105": "朝阳区"
    +"110106": "丰台区"
    +"110107": "石景山区"
    +"110108": "海淀区"
    +"110109": "门头沟区"
    // 以下省略 3000 多个地区
  }
}

但是解码为数组, county_list 里的原有索引会丢失。

array:3 [
  "province_list" => array:31 [
    110000 => "北京市"
    120000 => "天津市"
    130000 => "河北省"
    140000 => "山西省"
    150000 => "内蒙古自治区"
    210000 => "辽宁省"
    220000 => "吉林省"
    // 以下省略 20 多个地区
  ]
  "city_list" => array:344 [
    110100 => "市辖区"
    120100 => "市辖区"
    130100 => "石家庄市"
    130200 => "唐山市"
    130300 => "秦皇岛市"
    130400 => "邯郸市"
    130500 => "邢台市"
    // 以下省略 300 多个地区
  ]
  "county_list" => array:3220 [ // 这里原有索引丢失了,变成从 0 开始重排
    0 => "东城区"
    1 => "西城区"
    2 => "朝阳区"
    3 => "丰台区"
    4 => "石景山区"
    5 => "海淀区"
    6 => "门头沟区"
    // 以下省略 3000 多个地区
  ]
]

也就是说, json_decode() 方法解码 json,当索引数组超过一定元素时,原有索引会丢失并重排。
有没有人研究过 json_decode() 方法解码 json ,索引数组最多可以容纳多少元素而不会导致原有索引丢失?这个和索引数组的维度是否相关?

Long2Ge
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
Oraoto
最佳答案

这个是dd() 的问题,直接遍历或者var_dump可以看到是没有重排的。

具体可以看 Symfony\Component\VarDumper\Cloner\VarCloner的处理。

4年前 评论
讨论数量: 8
long2ge

试图数组的形式访问解码对象,会报 Cannot use object of type stdClass as array 。

4年前 评论
long2ge

@long2ge 也就是说 $decoded['province_list'][110000] 是不允许的,必须要用 $decoded->province_list->{110000} 的形式获取值。

4年前 评论

建议看一下原始数据的格式

4年前 评论

回答你这个问题吧

也就是说 $decoded ['province_list'][110000] 是不允许的,必须要用 $decoded->province_list->{110000} 的形式获取值。

json_decode ( string $json [, bool $assoc = FALSE [, int $depth = 512 [, int $options = 0 ]]] ) : mixed

第二个参数,就是 decode 时候,是返回对象还是数据,你如果想要数组的话,就换成 true.

至于重置索引的问题,肯定不是元素内过多,大概率是数据源有问题,可以重复校验下。

4年前 评论
long2ge

这个地区缓存文件的内容是这样子的。

{
    "province_list": {
        "110000": "北京市",
        "120000": "天津市",
        "130000": "河北省",
        "140000": "山西省",
        "150000": "内蒙古自治区",
        "210000": "辽宁省",
        "220000": "吉林省"
    },
    "city_list": {
        "110100": "市辖区",
        "120100": "市辖区",
        "130100": "石家庄市",
        "130200": "唐山市",
        "130300": "秦皇岛市",
        "130400": "邯郸市",
        "130500": "邢台市"
    },
    "county_list": {
        "110101": "东城区",
        "110102": "西城区",
        "110105": "朝阳区",
        "110106": "丰台区",
        "110107": "石景山区",
        "110108": "海淀区",
        "110109": "门头沟区"
    }
}
4年前 评论
long2ge

@lxping 这个校验过了,文件内容是正确的 json 。
我现在的问题是解码为对象没有问题,解码为数组,县级地区列表的索引会被重排。
但解码为对象后是 \stdClass 的实例化,而这个和自定义的类的实例化不同,不能使用访问数组的形式访问。

4年前 评论
Oraoto

这个是dd() 的问题,直接遍历或者var_dump可以看到是没有重排的。

具体可以看 Symfony\Component\VarDumper\Cloner\VarCloner的处理。

4年前 评论
long2ge

@振翅飞翔 我这个缓存文件总共只有1行,不存在换行的问题。

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!