なぜ「JSON デコード(例外対応)」が必要なのか
業務で JSON を扱うとき、ほぼ必ずやるのが「文字列 → 配列(オブジェクト)」への変換、つまり JSON デコードです。
ここで怖いのは、「壊れた JSON が来たときに、気づかないまま処理が進んでしまう」ことです。
json_decode() は、失敗しても「静かに null を返す」ことがあります。
そのまま null を配列だと思ってアクセスすると、Warning やバグの原因になります。
だからこそ、「JSON が壊れていたら必ずエラーとして扱う」「どこで・なぜ失敗したか分かる」ようにする——
これが「例外対応付き JSON デコード」ユーティリティの目的です。
json_decode の基本と「落とし穴」
素の json_decode の挙動
まずは基本形です。
$json = '{"name":"山田太郎","age":20}';
$data = json_decode($json, true);
var_dump($data);
// array(2) { ["name"]=> string(12) "山田太郎" ["age"]=> int(20) }
PHP第二引数に true を渡すと「連想配列」、false か省略すると「オブジェクト」として返ってきます。
問題は、JSON が壊れていた場合です。
$badJson = '{"name":"山田太郎",}'; // 末尾に余計なカンマ
$data = json_decode($badJson, true);
var_dump($data);
// NULL
PHPnull が返ってきますが、「本当に JSON が壊れているのか」「JSON の中身が null なのか」が区別できません。
このまま $data['name'] などにアクセスすると、警告が出たり、ロジックが破綻します。
例外対応のキモ:JSON_THROW_ON_ERROR を使う
失敗したら例外を投げさせる
PHP 7.3 以降では、json_decode() にフラグ JSON_THROW_ON_ERROR を渡すことで、「失敗したら例外を投げる」モードにできます。
$json = '{"name":"山田太郎","age":20}';
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
PHP壊れた JSON を渡すと、JsonException が投げられます。
$badJson = '{"name":"山田太郎",}';
try {
$data = json_decode($badJson, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo 'JSON デコード失敗: ' . $e->getMessage();
}
PHPこれで、「壊れた JSON が来たのに気づかないまま処理が進む」という状態を防げます。
例外が飛べば、その場で止まるか、上位でキャッチしてエラーレスポンスを返すなど、明示的な対応ができます。
実務で使いやすい「ラッパー関数」を作る
連想配列で返す版
毎回 json_decode(..., true, 512, JSON_THROW_ON_ERROR) と書くのは面倒なので、
ユーティリティ関数にまとめてしまうのがおすすめです。
/**
* JSON 文字列を「連想配列」としてデコードする(失敗時は JsonException)
*/
function json_decode_array(string $json): array
{
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
PHP使い方の例です。
try {
$data = json_decode_array($requestBody);
// ここまで来れば $data は必ず配列
echo $data['name'] ?? '名前なし';
} catch (JsonException $e) {
// 400 Bad Request などを返す
http_response_code(400);
echo '不正な JSON です: ' . $e->getMessage();
}
PHPここでの重要ポイントは、「戻り値の型がはっきりしている」ことです。array を返すと決めておけば、呼び出し側は「配列として扱っていい」と安心してコードを書けます。
オブジェクトで返す版
オブジェクトとして扱いたい場合のラッパーも用意できます。
/**
* JSON 文字列を「オブジェクト」としてデコードする(失敗時は JsonException)
*/
function json_decode_object(string $json): object
{
$result = json_decode($json, false, 512, JSON_THROW_ON_ERROR);
// 念のため型を保証
if (!is_object($result)) {
throw new RuntimeException('JSON はオブジェクトではありません');
}
return $result;
}
PHP例題:API のリクエストボディを安全にパースする
よくある「危ない」書き方
例えば、JSON API のエンドポイントで、
リクエストボディをこう書いているコードがあったとします。
$body = file_get_contents('php://input');
$data = json_decode($body, true);
// ここで $data['name'] を使い始める…
PHPJSON が壊れていた場合、$data は null になり、$data['name'] で警告が出たり、意図しない挙動になります。
例外対応版に書き換える
これを、先ほどのユーティリティを使って書き換えます。
$body = file_get_contents('php://input');
try {
$data = json_decode_array($body);
} catch (JsonException $e) {
http_response_code(400);
echo 'リクエストボディが不正な JSON です。';
exit;
}
// ここから先は $data が必ず配列として使える
$name = $data['name'] ?? null;
PHPこうしておけば、「JSON が壊れている」という入力エラーを、
アプリケーションのロジックエラーと混同せずに扱えます。
json_last_error 系との違いと使い分け
古い書き方:json_last_error を使う
JSON_THROW_ON_ERROR がない時代は、こんな書き方がよく使われていました。
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
// エラー処理
}
PHPこれはこれで動きますが、
毎回 json_last_error() を呼ぶのを忘れがち
どこで失敗したかがコード上で分かりにくい
戻り値の型が null か配列か曖昧
といった弱点があります。
今の時代のおすすめは「例外ベース」
JSON_THROW_ON_ERROR を使えば、
失敗した瞬間に例外が飛ぶ
try-catch の範囲で「ここで JSON が壊れていたらエラーにする」と明示できる
戻り値の型を関数のシグネチャで固定しやすい
というメリットがあります。
初心者のうちから「JSON デコードは例外で扱う」という癖をつけておくと、
後からコードを読む人(未来の自分も含む)がかなり楽になります。
まとめ:今日からの「JSON デコード(例外対応)」ユーティリティ
押さえておきたいポイントは、次のとおりです。
json_decode() は失敗しても静かに null を返すので、そのまま使うとバグの温床になる。JSON_THROW_ON_ERROR フラグを使えば、壊れた JSON で必ず JsonException が飛ぶ。
「配列用」「オブジェクト用」のラッパー関数を作っておくと、呼び出し側のコードがすっきりする。
実務ユーティリティとしては、まずこの 2 本を持っておくとかなり安心です。
function json_decode_array(string $json): array
{
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
function json_decode_object(string $json): object
{
$result = json_decode($json, false, 512, JSON_THROW_ON_ERROR);
if (!is_object($result)) {
throw new RuntimeException('JSON はオブジェクトではありません');
}
return $result;
}
PHPもし、あなたのプロジェクトのどこかで「json_decode(...); の戻り値をそのまま信じて使っている」コードを見つけたら、そこがこのユーティリティに差し替えるべきポイントです。
その一箇所を直すだけで、「壊れた JSON に気づかないまま処理が進む」という事故をかなり減らせます。
