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

PHP 陣列與 JSON 互轉完全指南:json_encode/json_decode 深度解析與最佳實踐

     編輯:PHP 相關知識

JSON(JavaScript Object Notation)已成為 Web API 數據交換的標準格式。PHP 提供 json_encode() 和 json_decode() 兩大核心函數,實現陣列/物件與 JSON 字符串的高效雙向轉換。本文系統梳理參數選項、編碼規則、常見陷阱與性能優化策略。

一、json_encode():PHP 值 → JSON 字符串

函數簽名

json_encode(mixed $value, int $flags = 0, int $depth = 512): string|false

常用標誌位(Flags)

常量作用推薦場景
JSON_UNESCAPED_UNICODE不義 Unicode 字符(中文直接輸出)強烈推薦,提升可讀性、減小體積
JSON_UNESCAPED_SLASHES不轉義 / 字符URL、路徑包含斜槿時
JSON_HEX_TAG轉義 < > & 為 \u003C 等直接嵌入 HTML <script> 標籤時防 XSS
JSON_HEX_APOS轉義 ' 為 \u0027嵌入 HTML 屬性值(單引號包裹)
JSON_HEX_QUOT轉義 " 為 \u0022嵌入 HTML 屬性值(雙引號包裹)
JSON_NUMERIC_CHECK數字字符串轉為數值類型謹慎使用,可能導致精度丟失(如大整數、手機號)
JSON_PRETTY_PRINT格式化縮進輸出調試、日誌、配置文件生成
JSON_PRESERVE_ZERO_FRACTION保留浮點數 .0(如 1.0 不變 1)需嚴格區分整數/浮點的 API
JSON_FORCE_OBJECT索引陣列強制輸出為物件API 要求物件格式
JSON_THROW_ON_ERROR錯誤拋出 JsonException(PHP 7.3+)現代錯誤處理,避免靜默失敗

基礎範例

<?php
$assoc = ['name' => '張三', 'age' => 25, 'tags' => ['php', 'json', 'api']];
$indexed = ['蘋果', '香蕉', '橙子'];

// 關聯陣列 → JSON 物件
echo json_encode($assoc, JSON_UNESCAPED_UNICODE);
// {"name":"張三","age":25,"tags":["php","json","api"]}

// 索引陣列 → JSON 陣列
echo json_encode($indexed, JSON_UNESCAPED_UNICODE);
// ["蘋果","香蕉","橙子"]

// 強制索引陣列輸出為物件
echo json_encode($indexed, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT);
// {"0":"蘋果","1":"香蕉","2":"橙子"}

// 格式化輸出(調試用)
echo json_encode($assoc, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
/*
{
    "name": "張三",
    "age": 25,
    "tags": [
        "php",
        "json",
        "api"
    ]
}
*/
?>

特殊值處理

<?php
$data = [
    'null' => null,
    'true' => true,
    'false' => false,
    'int' => 123,
    'float' => 3.14,
    'inf' => INF,
    'nan' => NAN,
    'empty_arr' => [],
    'empty_obj' => new stdClass(),
];

echo json_encode($data, JSON_UNESCAPED_UNICODE);
// {"null":null,"true":true,"false":false,"int":123,"float":3.14,"inf":null,"nan":null,"empty_arr":[],"empty_obj":{}}
// 注意:INF/NAN 會變為 null,空陣列為 [],空物件為 {}
?>

二、json_decode():JSON 字符串 → PHP 值

函數簽名

json_decode(string $json, bool $associative = false, int $depth = 512, int $flags = 0): mixed

關鍵參數:$associative

  • false(預設):返回 stdClass 物件
  • true:返回關聯陣列(強烈推薦,操作統一、性能略優)

常用標誌位

常量作用
JSON_BIGINT_AS_STRING大整數作為字符串返回(防精度丟失,PHP 5.4+)
JSON_OBJECT_AS_ARRAY等同 $associative=true(PHP 7.2+)
JSON_THROW_ON_ERROR錯誤拋出 JsonException(PHP 7.3+)

範例

<?php
$json = '{"id":1234567890123456789,"name":"李四","active":true,"scores":[95,87,92]}';

// 返回物件(預設)
$obj = json_decode($json);
echo $obj->name; // 李四
echo $obj->id;   // 1.2345678901235E+18 (精度丟失!)

// 返回關聯陣列(推薦)
$arr = json_decode($json, true);
echo $arr['name']; // 李四

// 大整數保持字符串(防精度丟失)
$arrSafe = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
echo $arrSafe['id']; // "1234567890123456789" (精確保留)

// 錯誤處理(PHP 7.3+)
try {
    $data = json_decode($invalidJson, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    error_log("JSON 解析失敗: " . $e->getMessage());
}
?>

三、深度嵌套與遞歸限制

預設最大深度 512,超過返回 false 並觸發錯誤。可通過第三參數調整:

<?php
$deep = '[[[[[...]]]]]'; // 超過 512 層
json_decode($deep, true, 1024); // 提高限制
?>

四、錯誤檢測與處理

PHP 7.3+ 現代方式(推薦)

<?php
function safeJsonDecode(string $json, bool $assoc = true): array|object|null {
    try {
        return json_decode($json, $assoc, 512, JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        error_log("JSON 解析錯誤: {$e->getMessage()} at position {$e->getCode()}");
        return null; // 或拋出自定義異常
    }
}
?>

舊版本兼容方式

<?php
$json = '{"a":1}';
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    error_log("JSON 錯誤: " . json_last_error_msg());
    // 處理錯誤...
}
?>

五、常見陷阱與避坑指南

陷阱原因解決方案
中文變 \uXXXX預設轉義 Unicode使用 JSON_UNESCAPED_UNICODE
大整數精度丟失PHP 浮點數精度限制(IEEE 754)解碼用 JSON_BIGINT_AS_STRING;編碼端確保傳字符串
空陣列 [] vs 空物件 {}PHP 陣列無法區分索引/關聯用 JSON_FORCE_OBJECT 強制物件;或確保鍵非連續數字
INF/NAN 變 nullJSON 標準不支援序列化前檢查 is_finite(),轉為字符串或 null
循環引用導致錯誤物件/陣列相互引用實現 JsonSerializable 接口控制輸出;或斷開循環
BOM 頭導致解析失敗UTF-8 BOM (EF BB BF) 非 JSON 標準json_decode(ltrim($json, "\xEF\xBB\xBF"))

六、實戰最佳實踐

1. API 統一輸出封裝

<?php
function jsonResponse(mixed $data, int $code = 200, string $message = ''): void {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    
    $payload = [
        'code' => $code,
        'message' => $message,
        'data' => $data,
        'timestamp' => time(),
    ];
    
    echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

// 使用
jsonResponse(['user_id' => 123], 200, '登錄成功');
?>

2. 實現 JsonSerializable 精確控制序列化

<?php
class User implements JsonSerializable {
    private int $id;
    private string $name;
    private string $password; // 敏感字段
    private DateTime $createdAt;
    
    public function jsonSerialize(): array {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'created_at' => $this->createdAt->format('c'), // ISO 8601
            // 故意不輸出 password
        ];
    }
}

$user = new User(1, 'admin', 'secret', new DateTime());
echo json_encode($user, JSON_UNESCAPED_UNICODE);
// {"id":1,"name":"admin","created_at":"2024-01-15T10:30:00+08:00"}
?>

3. 大數據流式處理(避免記憶體溢出)

對於超大 JSON,使用 halaxa/json-machine 等流式解析庫,而非一次性 json_decode()。

七、性能優化建議

  1. 復用編碼結果:相同數據多次輸出時緩存 JSON 字符串。
  2. 避免 JSON_PRETTY_PRINT 生產環境:增加 20-30% 體積,僅調試使用。
  3. 批量編碼優於循環編碼:json_encode($bigArray) 遠快於循環 json_encode($item)。
  4. 考慮 igbinary/msgpack:內部緩存/隊列序列化,比 JSON 快 2-5 倍、體積小 30-50%。

掌握 json_encode/decode 的參數組合、錯誤處理、精度控制與序列化定制,能讓你構建高效、健壯、可互操作的 API 服務。現代 PHP 開發中,統一使用關聯陣列、啟用 UNESCAPED_UNICODE、善用 JSON_THROW_ON_ERROR 是專業的標誌。

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