かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

PHP JSON デコードのエラーハンドリングのメモ

PHPJSON ファイルを読み込んでデコードに失敗しても例外ではなく null が返りエラーになったことに気づきづらいので例外を発生させるメモ

<?php
$json = "{";
$data = json_decode($json, true);
var_dump($data); // => NULL

JSON ファイルを読み込んで配列にして返したい

<?php
function loadFile(string $file): string {
  if ( !is_file($file) ) {
    throw new \Exception("{$file} is not a file");
  }
  $contents = file_get_contents($file);
  if ( $contents === false ) {
    throw new \Exception("Error reading file at {$file}");
  }
  return $contents;
}

function jsonDecode(string $jsonFile): array {
  $json = loadFile($jsonFile);
  // JSON のデコードに失敗しても NULL が返るのをどうにかしたい
  $data = json_decode($json, true);
  return $data;
}

1. json_last_error でエラーをキャッチする

json_last_error は直前に発生したエラーを返す
cf. PHP: json_last_error - Manual

json_last_error で返されるエラーの種類は定数で、実際のエラーメッセージは json_last_error_msg で取得できる

<?php
function jsonDecode(string $jsonFile): array {
  $json = loadFile($jsonFile);
  $data = json_decode($json, true);
  // JSON decode のエラー
  if ( json_last_error() !== \ JSON_ERROR_NONE ) {
    throw new \InvalidArgumentException("Error of parsing JSON.\n" . json_last_error_msg() . ":" . json_last_error());
  }
  return $data;
}
// エラーのキャッチ
try {
  $jsonData = jsonDecode($jsonFile);
} catch ( \InvalidArgumentException $e ) {
  // JSON decode error
}

cf.

2. JSON_THROW_ON_ERROR オプションを使う (PHP > 7.3)

json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) 第4引数に JSON_THROW_ON_ERROR を渡すとデコードのエラーがある場合に JsonException を発生させる

JSON_THROW_ON_ERROR
エラーが起きた場合、 json_last_error() や json_last_error_msg() 関数で収集される、 グローバルなエラー状態を設定するかわりに、 JsonException をスローします。 JSON_PARTIAL_OUTPUT_ON_ERROR は JSON_THROW_ON_ERROR よりも優先します。 PHP 7.3.0 以降で使用可能です。
cf. PHP: 定義済み定数 - Manual

<?php
function jsonDecode(string $jsonFile): array {
  $json = loadFile($jsonFile);
  $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
  return $data;
}
// エラーのキャッチ
try {
  $jsonData = jsonDecode($jsonFile);
} catch ( \JsonException $e ) {
  // JSON decode error
}

cf.

所管

流石にもう多くのプロジェクトでは PHP v7.4 以上だと思うので JSON_THROW_ON_ERROR オプションを使う方がエラーも独自の JsonException なのでエラーハンドリングするのに良さそうかな〜と思いました。
おわり ₍ ᐢ. ̫ .ᐢ ₎


[参考]