json_encode() 是 PHP 將陣列/物件序列化為 JSON 字串的核心函式。本文從資料庫查詢、陣列組裝、編碼選項、前端 AJAX 接收、常見坑點 (中文 Unicode、大數字精度、循環引用) 完整說明,並示範輸出供 ECharts/Chart.js 直接使用的資料結構。
[xData, yData, labels])json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)Content-Type: application/json; charset=utf-8 輸出<?php
// columndata.php
header('Content-Type: application/json; charset=utf-8');
try {
$pdo = new PDO(
'mysql:host=localhost;dbname=stats;charset=utf8mb4',
'user', 'pass',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$begin = $_GET['BeginTime'] ?? date('Y-m-01');
$end = $_GET['EndTime'] ?? date('Y-m-d');
$kw = $_GET['keyword'] ?? '';
$sql = 'SELECT `EventDate`, `data` FROM `metrics`
WHERE `EventDate` BETWEEN ? AND ?'
. ($kw ? ' AND `tag` LIKE ?' : '')
. ' ORDER BY `EventDate`';
$params = [$begin, $end];
if ($kw) $params[] = "%{$kw}%";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$xData = [];
$yData = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$xData[] = $row['EventDate']; // 日期字串
$yData[] = (int) $row['data']; // 強制整數
}
// 組裝前端 ECharts/Chart.js 直接可用的結構
$payload = [
'xAxis' => $xData,
'series' => [[
'name' => '數值',
'type' => 'line',
'data' => $yData,
]],
'meta' => [
'count' => count($xData),
'generated' => date('c'),
],
];
// 關鍵選項說明:
// JSON_UNESCAPED_UNICODE : 中文不轉 \uXXXX,減小體積且可讀
// JSON_UNESCAPED_SLASHES : 不轉義 /,URL 更乾淨
// JSON_NUMERIC_CHECK : 數字字串轉真數字 (謹慎用,大整數可能溢位)
// JSON_PRESERVE_ZERO_FRACTION : 保留 1.0 不變 1
echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
}
// 現代 Fetch API (推薦)
async function loadChartData() {
const params = new URLSearchParams({
BeginTime: '2024-01-01',
EndTime: '2024-12-31',
keyword: 'sales'
});
const resp = await fetch(`columndata.php?${params}`);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json(); // 自動解析 JSON
// data 結構:{ xAxis: [...], series: [{data: [...]}], meta: {...} }
initChart(data.xAxis, data.series[0].data);
}
// 傳統 jQuery (相容舊專案)
$.ajax({
url: 'columndata.php',
dataType: 'json', // 自動 parseJSON
cache: false,
data: { BeginTime: '2024-01-01', EndTime: '2024-12-31' },
success: function (data) {
if (data.error) return alert(data.error);
initChart(data.xAxis, data.series[0].data);
},
error: function () { alert('請求失敗'); }
});
| 現象 | 原因 | 解決 |
|---|---|---|
| 中文變 \uXXXX | 預設逃逸 Unicode | 加 JSON_UNESCAPED_UNICODE |
| URL 變 http:\/\/example.com | 預設逃逸斜線 | 加 JSON_UNESCAPED_SLASHES |
| 大整數 (ID) 變科學記號或失真 | JS Number 53-bit 限制 | 後端輸出字串 "id": "1234567890123456789",前端用 BigInt 或字串處理 |
| 浮點數 0.1+0.2=0.30000000000004 | IEEE 754 二進制浮點 | 資料庫存 DECIMAL(10,2),PHP 用 number_format($v, 2, '.', '') 或 bcmath |
| 循環引用錯誤 (Recursion detected) | 物件互相參考 | 實作 JsonSerializable 或用 DTO 陣列 |
| 前端收到字串而非物件 | 未送 Content-Type: application/json | 確實送標頭,或前端 JSON.parse() |
class ChartDataset implements JsonSerializable
{
private array $xAxis;
private array $yData;
private string $label;
public function __construct(array $x, array $y, string $label)
{
$this->xAxis = $x;
$this->yData = $y;
$this->label = $label;
}
public function jsonSerialize(): array
{
return [
'labels' => $this->xAxis,
'datasets' => [[
'label' => $this->label,
'data' => $this->yData,
'borderColor' => 'rgb(54, 162, 235)',
'backgroundColor' => 'rgba(54, 162, 235, 0.2)',
'fill' => false,
'tension' => 0.1,
]],
];
}
}
// 使用
$dataset = new ChartDataset($dates, $values, '銷售額');
echo json_encode($dataset, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
EventDate、tag 加索引,避免全表掃描。LIMIT 365。ETag / Cache-Control: max-age=60,減少重複請求。gzip_types application/json,JSON 壓縮率極高 (常 >80%)。