問題点
夜遅く、ようやくAPI連携の作業が終わりかけているとします。外部サービスは有効なJSONレスポンスを返し、あなたは json_decode() を呼び出し、値を取得しようとしました。すると突然、スクリプトがクラッシュします。
$response = file_get_contents('https://api.example.com/user/1');
$data = json_decode($response);
echo $data['username']; // これが致命的エラー(Fatal Error)を引き起こします
ユーザー名の代わりに、ぶっきらぼうなエラーメッセージが表示されます:Fatal error: Cannot use object of type stdClass as array。コードの実行はそこで完全に止まってしまいます。
原因
デフォルトでは、json_decode($json) は stdClass 型のオブジェクトを返します。PHPでは、ArrayAccess インターフェースを実装していない限り、オブジェクトに対して角括弧($data['key'])を使用することはできません。stdClass は単なる汎用的な空のコンテナであるため、アロー演算子(->)しか認識しません。
これは、取っ手しかないドアに鍵を使おうとするようなものです。構文が構造と一致していません。
1秒でできる修正:Booleanフラグを使用する
最も手っ取り早い解決策は、json_decode() の第2引数に true を渡すことです。これにより、PHPはオブジェクトの代わりに連想配列を返すようになります。配列の方がループ処理などで扱いやすいため、多くの開発者がこの方法を好みます。
// これを:
$data = json_decode($response);
// このように変更します:
$data = json_decode($response, true);
// これで正常に動作します:
echo $data['username'];
別の方法:オブジェクト構文のまま進める
アプリの他の部分でその形式が期待されている場合など、データをオブジェクトのまま保持したいこともあります。その場合は、角括弧をアロー演算子に書き換えるだけです。こちらの方が記述がすっきりし、一部のPHPバージョンではわずかに高速です。
$data = json_decode($response);
// オブジェクトのプロパティとしてアクセス
echo $data->username;
JSONのキーに user-id のようにハイフンが含まれている場合はどうすればよいでしょうか? $data->user-id と書くと、PHPは定数を引き算しようとしていると解釈してしまいます。その場合は、波括弧を使用します:$data->{'user-id'}。
深くネストされたデータの取り扱い
このエラーが最も厄介なのは、ネストされたJSONを扱う時です。{"meta": {"status": 200}} のような構造を想像してください。true フラグを忘れると、$data['meta']['status'] は最初の括弧の時点で失敗します。
PHPが実際に何を扱っているかを確認するには、var_dump($data) を実行してください。class stdClass と表示されればアロー演算子を、array と表示されれば角括弧を使用します。これが、コードを書き進める前にデータ構造を確認する最短の方法です。
検証と安全性
APIが常に有効なデータを返すと決めつけないでください。よくある間違いは、JSONの形式が崩れているために null 値に対して配列アクセスを試みてしまうことです。コードを本番環境で使えるレベルにするために、簡単なチェックを追加しましょう。
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("無効なJSONを受信しました: " . json_last_error_msg());
}
if (isset($data['username'])) {
echo "ユーザー: " . $data['username'];
}
プロのヒント:生のJSONを検査する
奇妙なAPIレスポンスをデバッグする際、私はよく生の文字列をフォーマッターにコピーして階層を視覚化します。私はよく ToolCraftのJSON Formatter & Validator を使っています。これはブラウザ上ですべて完結するため、機密性の高い本番データやAPIキーがサードパーティのサーバーに送信される心配がありません。
修正方法のまとめ:
- **配列の場合:** `json_decode($json, true);` を使用し、`$data['key']` でアクセスします。
- **オブジェクトの場合:** `json_decode($json);` を使用し、`$data->key` でアクセスします。
- **デバッグ:** 結果が `null` の場合は `json_last_error()` を確認します。

