タイトル: 配列からJSONに変換
SEOタイトル: PHP 配列→JSON 変換 (json_encode) 完全ガイド(フラグ / UTF-8 / json_last_error)
| この記事の要点 |
|
基本: 配列を JSON 文字列に変換
'山田太郎',
'age' => 30,
'tags' => ['php', 'javascript'],
];
echo json_encode($data);
// → {"name":"山田太郎","age":30,"tags":["php","javascript"]}
// 日本語が \uXXXX エスケープされてしまう
echo json_encode($data, JSON_UNESCAPED_UNICODE);
// → {"name":"山田太郎","age":30,"tags":["php","javascript"]}
// そのまま日本語で出る (推奨)
主要フラグ一覧
| フラグ | 意味 | 定番 |
|---|---|---|
JSON_UNESCAPED_UNICODE | 日本語等を \uXXXX にエスケープしない | ★ |
JSON_UNESCAPED_SLASHES | / をエスケープしない (URL を含む時) | ★ |
JSON_PRETTY_PRINT | 整形 (改行 + インデント) | デバッグ用 |
JSON_THROW_ON_ERROR | エラー時に JsonException 投げる (PHP 7.3+) | ★ 必須 |
JSON_NUMERIC_CHECK | 数値文字列を数値に変換 (危険) | 非推奨 |
JSON_FORCE_OBJECT | 空配列も {} として出力 | 状況による |
JSON_PRESERVE_ZERO_FRACTION | 1.0 を 1 にしない | ★ |
JSON_HEX_TAG 等 | HTML 安全エスケープ | script 出力時 |
推奨デフォルト
true, 'data' => $rows]);
連想配列と index 配列の違い
PHP の配列は JSON にエンコードする際、キーが連続した整数かどうかで出力が変わります:
'taro', 'age' => 30];
echo json_encode($assoc);
// → {"name":"taro","age":30}
// 飛び番の整数キー → JSON Object になる
$mixed = [0 => 'a', 2 => 'b', 5 => 'c'];
echo json_encode($mixed);
// → {"0":"a","2":"b","5":"c"}
// 配列ではなくオブジェクト扱いになるので注意
// 強制的に Object 化
echo json_encode([], JSON_FORCE_OBJECT); // → {}
echo json_encode([]); // → [] (デフォルト)
null / false / int の挙動
エラーハンドリング
getMessage());
http_response_code(500);
exit;
}
// よくあるエラー原因
// - UTF-8 でない文字列 (SJIS のままなど)
// - INF / NAN を含む
// - 循環参照 (オブジェクトが自分自身を参照)
// - リソース型を含む (file handle 等)
UTF-8 エンコーディング
JSON はUTF-8 必須です。SJIS / EUC-JP / CP932 のままだと json_encode() は false を返します:
mb_convert_encoding('山田', 'SJIS', 'UTF-8')];
$json = json_encode($bad); // → false
echo json_last_error_msg(); // → Malformed UTF-8 characters, possibly incorrectly encoded
// 対処: 先に UTF-8 化
function toUtf8($s) {
return mb_convert_encoding($s, 'UTF-8', 'auto');
}
function deepUtf8($v) {
if (is_string($v)) return mb_convert_encoding($v, 'UTF-8', 'auto');
if (is_array($v)) return array_map('deepUtf8', $v);
return $v;
}
$json = json_encode(deepUtf8($data), JSON_UNESCAPED_UNICODE);
JSON → 配列 (逆変換)
'taro', 'tags' => ['a','b']]
// stdClass オブジェクトで受ける (デフォルト)
$obj = json_decode($json);
echo $obj->name; // taro
echo $obj->tags[0]; // a
// 例外化
try {
$arr = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
error_log($e->getMessage());
}
// ネストの深さ制限 (第三引数、デフォルト 512)
$arr = json_decode($json, true, 1024);
Laravel での JSON 出力
json($data);
// フラグ指定
return response()->json($data,
200,
['Content-Type' => 'application/json; charset=UTF-8'],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
// Laravel グローバル設定 (config/app.php に追記)
// 'json' => [
// 'encode_options' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
// ],
// Eloquent モデルの toJson
class User extends Model {
protected $hidden = ['password']; // JSON に含めない
protected $casts = [
'options' => 'array', // DB の JSON 列を自動デコード
'is_admin' => 'boolean',
];
}
echo $user->toJson(JSON_UNESCAPED_UNICODE);
// Resource (整形)
class UserResource extends JsonResource {
public function toArray($req): array {
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at?->toIso8601String(),
];
}
}
return new UserResource($user);
JsonSerializable インターフェース
独自クラスを json_encode() に渡したときの出力を制御:
$this->amount,
'currency' => $this->currency,
'formatted' => number_format($this->amount) . ' ' . $this->currency,
];
}
}
echo json_encode(new Money(1500));
// → {"amount":1500,"currency":"JPY","formatted":"1,500 JPY"}
FAQ
Q: 日本語が 山田 になってしまう
A: JSON_UNESCAPED_UNICODE フラグを付ければ 山田 のまま出力されます。
Q: HTML/script タグ内に出力するとき XSS が心配
A: JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT で < 等を 16 進エスケープし、HTML 内に安全に埋め込めます。
Q: 大きな配列を JSON 化するとメモリ不足になる
A: JsonMachine 等のストリーミング JSON エンコーダ、または chunk して NDJSON 出力を検討。