首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP JSON 編碼深度解析:陣列 vs 物件輸出差異、json_encode 強制類型與最佳實踐

     編輯:PHP 相關知識

PHP json_encode() 核心機制:Vector/Map 雙重身分、索引連續性判斷與強制輸出控制

PHP 陣列同時具備「有序列表」(Vector) 與「鍵值對應」(Map) 兩重特性,導致 json_encode() 輸出格式在陣列與物件之間切換,造成前後端介接困擾。本文深度解析判斷邏輯、強制輸出技巧與架構層面解決方案。

核心判斷邏輯:何時輸出陣列 [],何時輸出物件 {}

// ✅ 輸出 JSON 陣列 [] 的條件 (Vector):
// 1. 所有鍵為整數
// 2. 從 0 開始
// 3. 連續遞增 (0, 1, 2, 3...)
// 4. 順序不可變動

$vector = [12, 23, 18];                    // [12,23,18]
$vector2 = [0 => 12, 1 => 23, 2 => 18];   // [12,23,18]

// ❌ 輸出 JSON 物件 {} 的情況 (Map):
$map1 = [0 => 12, 1 => 23, 3 => 18];      // 跳過 2 -> {"0":12,"1":23,"3":18}
$map2 = [1 => 12, 2 => 23];               // 不從 0 開始 -> {"1":12,"2":23}
$map3 = ['a' => 1, 'b' => 2];             // 字串鍵 -> {"a":1,"b":2}
$map4 = [2 => 'a', 0 => 'b'];             // 順序錯誤 -> {"2":"a","0":"b"}

強制輸出控制選項

$data = [1, 2, 3];

// 1. 強制輸出物件
json_encode((object)$data);                    // {"0":1,"1":2,"2":3}
json_encode($data, JSON_FORCE_OBJECT);         // {"0":1,"1":2,"2":3}

// 2. 保留分數精度 (PHP 7.1+)
json_encode(1.5, JSON_PRESERVE_ZERO_FRACTION); // 1.50

// 3. Unicode 不轉義 (PHP 5.4+)
json_encode('中文', JSON_UNESCAPED_UNICODE);   // "中文" 而非 "\u4e2d\u6587"

// 4. 斜線不轉義 (PHP 5.4+)
json_encode('https://example.com', JSON_UNESCAPED_SLASHES);

// 5. 組合選項
json_encode($data, JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE);

常見陷阱與除錯案例

// 陷阱 1:array_filter 導致鍵值不連續
$arr = [1, 2, 3, 4, 5];
$filtered = array_filter($arr, fn($x) => $x > 2);
// $filtered = [2 => 3, 3 => 4, 4 => 5] -> 物件輸出!

// 修正:重新索引
$filtered = array_values(array_filter($arr, fn($x) => $x > 2));
// [3, 4, 5] -> 陣列輸出

// 陷阱 2:unset 導致空洞
$arr = [1, 2, 3];
unset($arr[1]);
// [0 => 1, 2 => 3] -> 物件輸出

// 陷阱 3:資料庫查詢結果預設為關聯陣列
$users = User::find()->asArray()->all();
// 通常包含 'id', 'name' 等字串鍵 -> 物件輸出

// 陷阱 4:數值字串鍵
$arr = ['0' => 'a', '1' => 'b']; // 字串鍵!
json_encode($arr); // {"0":"a","1":"b"} 物件

// 強制轉換為整數鍵
$arr = array_map('intval', array_keys($arr)); // 不正確
// 正確:
$arr = array_combine(array_map('intval', array_keys($arr)), array_values($arr));

架構層面解決方案:封裝 Vector/Map 型別

// 定義明確型別類別
class JsonVector implements \JsonSerializable {
    private $data = [];
    
    public function __construct(array $items = []) {
        $this->data = array_values($items); // 強制重新索引
    }
    
    public function add($item) {
        $this->data[] = $item;
    }
    
    public function jsonSerialize() {
        return $this->data; // 保證輸出陣列
    }
}

class JsonMap implements \JsonSerializable {
    private $data = [];
    
    public function __construct(array $data = []) {
        $this->data = $data;
    }
    
    public function set($key, $value) {
        $this->data[$key] = $value;
    }
    
    public function jsonSerialize() {
        return $this->data; // 保證輸出物件
    }
}

// 使用
$vector = new JsonVector([1, 2, 3]);
$vector->add(4);
echo json_encode($vector); // [1,2,3,4] 保證陣列

$map = new JsonMap(['name' => 'John', 'age' => 30]);
echo json_encode($map); // {"name":"John","age":30} 保證物件

API 設計規範建議

資料類型JSON 格式PHP 型別建議範例
列表/集合陣列 []JsonVector / 索引陣列用戶列表、商品清單
單一實體/物件物件 {}JsonMap / 關聯陣列用戶詳情、訂單資訊
字典/查找表物件 {}JsonMap設定選項、狀態碼對照
樹狀結構巢狀物件/陣列遞迴型別選單結構、分類樹

前後端契約最佳實踐

  1. 定義 JSON Schema:使用 OpenAPI/Swagger 明確規範每個 API 回傳結構
  2. 統一回傳格式:{"code": 0, "data": [...], "message": ""},data 嚴格區分陣列/物件
  3. 自動化測試驗證:CI 流程中加入 JSON 結構驗證測試
  4. 文件化決策:記錄每個端點為何選擇陣列或物件,避免隨意變更

效能考量

  • JSON_FORCE_OBJECT 會略微增加編碼時間 (需建立物件結構)
  • 大量資料編碼前,先 array_values() 重新索引比強制轉物件更快
  • 避免在迴圈中重複 json_encode(),收集完整資料結構後一次編碼

理解 json_encode() 的 Vector/Map 判斷邏輯,是 PHP 後端與前端/行動端無縫對接的關鍵。架構層面引入明確型別封裝,能從根源消除格式不穩定問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved