自 PHP 5.2 起內建 json_encode() 與 json_decode(),成為前後端資料交換、API 回應、儲存結構化資料的標準工具。本文系統整理核心用法、常見陷阱與進階技巧。
$arr = ['a' => 1, 'b' => 2, 'c' => 3];
echo json_encode($arr); // {"a":1,"b":2,"c":3}
$obj = new stdClass();
$obj->id = 100;
$obj->name = 'Test';
echo json_encode($obj); // {"id":100,"name":"Test"}
| 旗標 | 用途 | 範例效果 |
|---|---|---|
JSON_UNESCAPED_UNICODE | 不轉義 Unicode(中文可讀) | "中文" 而非 "\u4e2d\u6587" |
JSON_UNESCAPED_SLASHES | 不轉義 / | "https://..." 而非 "https:\/\/..." |
JSON_HEX_TAG | 轉義 < > 防 XSS | 內嵌 HTML script 安全 |
JSON_HEX_APOS | 轉義單引號 | \u0027 |
JSON_HEX_QUOT | 轉義雙引號 | \u0022 |
JSON_HEX_AMP | 轉義 & | \u0026 |
JSON_NUMERIC_CHECK | 數值字串轉數值 | "123" → 123(謹慎使用) |
JSON_PRETTY_PRINT | 美化縮排 | 除錯/日誌易讀 |
JSON_FORCE_OBJECT | 索引陣列強制輸出物件 | ["a","b"] → {"0":"a","1":"b"} |
JSON_THROW_ON_ERROR | 錯誤拋出例外(PHP 7.3+) | 避免靜默失敗 |
$defaultFlags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_THROW_ON_ERROR; $json = json_encode($data, $defaultFlags);
$indexed = ['apple', 'banana', 'cherry'];
echo json_encode($indexed); // ["apple","banana","cherry"] → JS 陣列
$assoc = ['a' => 'apple', 'b' => 'banana'];
echo json_encode($assoc); // {"a":"apple","b":"banana"} → JS 物件
// 強制索引陣列輸出為物件
echo json_encode($indexed, JSON_FORCE_OBJECT); // {"0":"apple","1":"banana","2":"cherry"}
class User
{
public string $name;
private string $email; // 私有屬性預設不輸出
protected string $role; // 受保護屬性預設不輸出
public const TYPE = 'admin'; // 常數不輸出
public function __construct(string $name, string $email, string $role)
{
$this->name = $name;
$this->email = $email;
$this->role = $role;
}
// 自訂序列化(PHP 8.1+ 可用 __serialize)
public function jsonSerialize(): array
{
return [
'name' => $this->name,
'email' => $this->email, // 選擇性暴露
'role' => $this->role,
];
}
}
$user = new User('John', 'john@example.com', 'admin');
echo json_encode($user); // {"name":"John","email":"john@example.com","role":"admin"}
$json = '{"a":1,"b":2}';
$obj = json_decode($json);
echo $obj->a; // 1
echo get_class($obj); // stdClass
$arr = json_decode($json, true); // 第二參數 true echo $arr['a']; // 1 echo gettype($arr); // array
// 第 3 參數:最大深度(預設 512)
$deep = json_decode(str_repeat('{"a":', 1000) . '1' . str_repeat('}', 1000), true, 512); // null,超過深度
// 第 4 參數:選項旗標(PHP 7.3+)
$json = '{"id": 9007199254740993}'; // 超過 IEEE 754 安全整數
$obj = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
echo $obj->id; // "9007199254740993" 字串,避免精度遺失
| 錯誤 JSON | 原因 | 正確寫法 |
|---|---|---|
{'a':1} | 單引號非標準 | {"a":1} |
{a:1} | 鍵名未加雙引號 | {"a":1} |
{"a":1,} | 尾隨逗號 | {"a":1} |
undefined | 非 JSON 值 | null |
NaN/Infinity | 非 JSON 數值 | null 或字串 |
function safeJsonDecode(string $json, bool $assoc = true): array|object|null
{
try {
return json_decode($json, $assoc, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
} catch (JsonException $e) {
error_log('JSON 解析失敗: ' . $e->getMessage() . ' | 輸入: ' . mb_substr($json, 0, 200));
return null;
}
}
json_encode 比 serialize 快且跨語言相容。jsond 擴展)。掌握 JSON 旗標與錯誤處理,能建構穩健、高效、跨平台相容的資料交換介面。