匿名类 与 索引重建

本文主要介绍匿名类与索引重建在json 编码方面的一些小技巧

问题

将下面源数据结构 json 转为目标 json
json 数据

{
    "code": 200,
    "message": "操作成功",
    "data": [
        {
            "id": 1,
            "goods_id": 1,
            "property_name_id": 1,
            "property_value_id": 1,
            "property_name": {
                "title": "份量",
                "is_sale": true
            },
            "property_value": {
                "id": 1,
                "value": "小份",
                "image": ""
            }
        },
        {
            "id": 2,
            "goods_id": 1,
            "property_name_id": 1,
            "property_value_id": 2,
            "property_name": {
                "title": "份量",
                "is_sale": true
            },
            "property_value": {
                "id": 2,
                "value": "中份",
                "image": ""
            }
        },
        {
            "id": 3,
            "goods_id": 1,
            "property_name_id": 2,
            "property_value_id": 4,
            "property_name": {
                "title": "温度",
                "is_sale": true
            },
            "property_value": {
                "id": 4,
                "value": "常温",
                "image": ""
            }
        },
        {
            "id": 4,
            "goods_id": 1,
            "property_name_id": 2,
            "property_value_id": 5,
            "property_name": {
                "title": "温度",
                "is_sale": true
            },
            "property_value": {
                "id": 5,
                "value": "加冰",
                "image": ""
            }
        }
    ]
}

目标 json 结构

{
    "code": 200,
    "message": "操作成功",
    "data": [
        {
            "property_id": 1,
            "property_name": "份量",
            "is_sale": true,
            "items": [
                {
                    "id": 1,
                    "value": "小份",
                    "image": ""
                },
                {
                    "id": 2,
                    "value": "中份",
                    "image": ""
                }
            ]
        },
        {
            "property_id": 2,
            "property_name": "温度",
            "is_sale": true,
            "items": [
                {
                    "id": 4,
                    "value": "常温",
                    "image": ""
                },
                {
                    "id": 5,
                    "value": "加冰",
                    "image": ""
                }
            ]
        }
    ]
}

思路

  1. 将源json字符串直接解码为php对象obj
  2. 分析 获知主结构层级未变,但数据data内结构关系发生变更
  3. 重建data子项,该子项下的目标属性items下内容可从源中复用
  4. 将重建索引的data数组子项替代源data指向
  5. 对obj对象进行json编码

实现

更改引用类型数组的指向,以及用匿名类重建了data子项的一级实例对象元素。
另外,需要注意的是php关联数组,尤其是非0始的连续数字键关联数组数据,编码为json数组,需要重建索引。

 $obj = json_decode($json_str);

 $data = [];
 foreach($obj->data as $v){

   $nid=$v->property_name_id;
   if(!array_key_exists($nid,$data)){
       $o = new Class{};
       $o->property_id = $v->property_name_id;
       $o->property_name = $v->property_name->title;
       $o->is_sale= $v->property_name->is_sale ;
       $data[$nid]=$o;
   }
   $data[$nid]->items[]=$v->property_value;
 }

 $obj->data = array_values($data);
 echo json_encode($obj);

索引重建

作为弱类型语言php,在正常情况下是很踏实的扮演了这个角色,但在编码json时,如果你不通过var_dump打印一下它的原始类型,可能会发生一些你意料不到的情况。而即便是同一php类型,在不同的情况下它的json编码字符串也会不同。以php数组为例

$arr = ['a','b',3,false];
echo json_encode($arr),"\n";
$arr=['a','2'=>'b',3,false];
echo json_encode($arr),"\n";
$arr=['1'=>'a','2'=>'b'];
echo json_encode($arr),"\n";
$arr=['0'=>'a','1'=>'b'];
echo json_encode($arr),"\n";

猜猜输出的会都是json数组吗?,实际json效果如下

["a","b",3,false]
{"0":"a","2":"b","3":3,"4":false}
{"1":"a","2":"b"}
["a","b"]

类型系统

首先明确php数组不是json数组,二者是两套不同的类型系统。用过orm的同学知道,数据库语言类型(通常是sql)与你用的php数据类型有映射关系。这种映射大多数常用类型是可以找到另一种语言相同的类型(比如整型),但也有一些是找不到的。比如php中的字符串为键的关联数组,json中是不存在也不允许这样的数组。但在json中可以用键值对简单对象的形式来表示这种关联数组。

那你可能会问,第3个php数组为什么所有的键和第4个数组都是连续的数字序列,但第4个php数组进行json编码后是json数组,而第3个则是json对象??? 其实,聪明如你,可能猜到了,它的连续不是从0开始。

终点

好了,说了那么多,只是为了告知数字字符串的php关联数组索引重建再进行json编码会得到json数组。
一个有用的php原生就地重建函数 array_values($allocation_arr),还有同行函数,去手册找找看.....

至于实现中解码为php对象,主在于持有实例的引用,可调动引用所指向的数据,不必劳神解码为数组后进行多轮遍历,复制值,最大程度写尽可能少的有用代码。

本作品采用《CC 协议》,转载必须注明作者和本文链接
pardon110
讨论数量: 1

之前只用过 new stdclass https://3v4l.org/JSStn

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
开发者 @ 社科大
文章
134
粉丝
24
喜欢
101
收藏
55
排名:106
访问:8.9 万
私信
所有博文
社区赞助商