匿名類 與 索引重建

pardon110發表於2019-12-09

本文主要介紹匿名類與索引重建在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物件,主在於持有例項的引用,可調動引用所指向的資料,不必勞神解碼為陣列後進行多輪遍歷,複製值,最大程度寫儘可能少的有用程式碼。

相關文章