本文主要介紹匿名類與索引重建在
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": ""
}
]
}
]
}
思路
- 將源json字串直接解碼為php物件obj
- 分析 獲知主結構層級未變,但資料data內結構關係發生變更
- 重建data子項,該子項下的目標屬性items下內容可從源中複用
- 將重建索引的data陣列子項替代源data指向
- 對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物件,主在於持有例項的引用,可調動引用所指向的資料,不必勞神解碼為陣列後進行多輪遍歷,複製值,最大程度寫儘可能少的有用程式碼。