自 PHP 5.2 起內建 json_encode() / json_decode(),成為前後端數據交換、API 序列化、配置存儲的標準工具。但編碼限制、類型映射、錯誤處理等細節常被忽視。本文系統梳理核心用法、陷阱與最佳實踐。
| PHP 類型 | JSON 類型 | 示例 |
|---|---|---|
| array (索引數組,鍵為 0..n 連續整數) | Array [] | ['a','b'] → ["a","b"] |
| array (關聯數組/非連續鍵) | Object {} | [1=>'a',3=>'b'] → {"1":"a","3":"b"} |
| object (stdClass/自定義類) | Object {} | 僅編碼 **public** 屬性 |
| null / true / false / int / float | null / true / false / number | 直接映射 |
| resource | — | 編碼為 null 並拋警告 |
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
// JSON_UNESCAPED_UNICODE: 中文不轉 \uXXXX,可讀性↑、體積↓
// JSON_UNESCAPED_SLASHES: / 不轉 \/,URL 路徑更清爽
// JSON_NUMERIC_CHECK: 數值字符串 "123" 強制編碼為數字 123(謹慎用,可能改變語義)
// JSON_PRESERVE_ZERO_FRACTION: 1.0 保留 .0
// JSON_THROW_ON_ERROR: PHP 7.3+ 失敗拋 JsonException,替代 json_last_error()
json_encode(['a','b'], JSON_FORCE_OBJECT); // {"0":"a","1":"b"}
json_encode((object)['a','b']); // 同上
class User {
public $name = 'Tom';
private $password = 'secret'; // 不會被編碼
protected $role = 'admin'; // 不會被編碼
const TYPE = 'member'; // 不會被編碼
public function greet() {} // 方法不編碼
}
echo json_encode(new User()); // {"name":"Tom"}
需完整序列化對象(含私有屬性),實現 JsonSerializable 接口:
class User implements JsonSerializable {
private $password;
public function jsonSerialize(): array {
return ['name' => $this->name, 'role' => $this->role]; // 自定義輸出
}
}
json_decode(string $json, bool $associative = false, int $depth = 512, int $flags = 0): mixed
$associative = true:返回**關聯數組**而非 stdClass 對象(推薦統一用數組,便於數組函數處理)。$depth:最大遞歸深度,防止惡意深層嵌套導致棧溢出。$flags:JSON_BIGINT_AS_STRING 將超出 PHP 整數範圍的數字解析為字符串(避免精度丟失);JSON_THROW_ON_ERROR 同編碼端。{'foo':'bar'} ❌ → 必須雙引號 {"foo":"bar"}。{foo:"bar"} ❌。{"a":1,} ❌(JSON 不允許,JS 對象字面量允許)。{/*comment*/"a":1} ❌(標準 JSON 無註釋,需預處理移除)。json_encode() **要求輸入為 UTF-8 編碼**;非 UTF-8(如 GBK、Latin1)會導致字符變為 null 或空字符串。解決:
$data = ['msg' => '中文'];
// 若源數據為 GBK
$data['msg'] = mb_convert_encoding($data['msg'], 'UTF-8', 'GBK');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
try {
$arr = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
// 記錄 $e->getMessage()、$json 片段、請求上下文
throw new ApiException('Invalid JSON payload', 400, $e);
}
igbinary、msgpack 二進制序列化(需擴展)。json_encode 緩存結果(Key 含數據版本號)。halaxa/json-stream、salsify/json-streaming-parser。規範使用 JSON 選項、統一關聯數組模式、嚴格異常處理、編碼預檢,能消除 90% 以上線上 JSON 相關故障。