json_decodeで「nullが返ってくる」「エラーの原因がわからない」——公式マニュアルだけでは分かりにくいそんなつまずきに、コピペで使えるサンプルコード付きで答える記事です。json_decodeは、JSON文字列を配列やオブジェクトに変換する関数で、第2引数にtrueを渡すかどうかで戻り値の型が変わり、JSON文字列に問題があるとnullを返します。この記事では、配列・オブジェクトへの変換方法から、nullになる原因の切り分け方、json_last_errorを使ったエラー処理まで実例付きで解説します。
json_decodeで配列に変換する方法
JSONを配列として受け取るには、第2引数に true を指定します。これが最もよく使う基本形です。
$json = '{"name": "Taro", "age": 25}';
$data = json_decode($json, true);
echo $data['name']; // Taro
echo $data['age']; // 25
第2引数に true を渡すのがポイントです。省略すると配列ではなくオブジェクトとして返ります。
多次元配列の例
ネストされたJSONも true を指定すれば入れ子の連想配列として取得できます。
$json = '{
"user": {
"name": "Taro",
"address": {
"city": "Tokyo",
"zip": "100-0001"
}
},
"tags": ["php", "json", "laravel"]
}';
$data = json_decode($json, true);
echo $data['user']['name']; // Taro
echo $data['user']['address']['city']; // Tokyo
echo $data['tags'][0]; // php
JSON配列([])はPHPの添字配列、JSONオブジェクト({})は連想配列にそれぞれ対応します。
JSONとは
JSONは、データ構造を持つオブジェクトを簡潔に表現するためのフォーマットで、特にウェブサービスやAPIのレスポンスで利用されています。例えば、RESTful APIからデータを取得する際、JSONフォーマットで送信されることが多いです。JSONは、以下のようなキーと値のペアでデータを表現します。
{
"name": "John Doe",
"age": 30,
"isEmployed": true
}
PHPでJSONを扱う理由
JSONはその軽量さと柔軟性から、異なるプラットフォーム間でデータを交換する際に非常に便利です。PHPでは、JSONを扱うための組み込み関数が用意されており、その中でもjson_decodeを使用することで、JSONデータをPHPのネイティブなデータタイプに変換することができます。
json_decodeの基本的な使い方
json_decode関数は、JSON文字列をPHPの連想配列またはオブジェクトに変換するための関数です。以下に基本的な使用法を示します。
$jsonData = '{"name": "John Doe", "age": 30, "isEmployed": true}';
$array = json_decode($jsonData, true); // 連想配列に変換
$object = json_decode($jsonData); // オブジェクトに変換
print_r($array);
print_r($object);
配列とオブジェクトの違い
第2引数の指定によって戻り値の型が変わります。それぞれの特徴を整理します。
| 第2引数 | 戻り値の型 | 値へのアクセス | 主な用途 |
|---|---|---|---|
true |
連想配列(array) | $data['key'] |
一般的なデータ処理、Laravelでよく使う |
false(デフォルト) |
stdClassオブジェクト | $data->key |
オブジェクト指向で扱いたい場合 |
$json = '{"name": "John", "age": 30}';
// 配列として受け取る
$array = json_decode($json, true);
echo $array['name']; // John
// オブジェクトとして受け取る
$object = json_decode($json);
echo $object->name; // John
実務では true を指定して配列で受け取るほうが配列関数と相性が良く、コードが読みやすくなるためよく使われます。逆にPHPの配列やオブジェクトをJSON文字列に変換したい場合はjson_encodeを使います。使い方や注意点は「PHPでjson_encodeを使ってデータをJSON形式に変換する方法と注意点」で解説しています。
第一引数: JSON文字列
最初の引数には、変換したいJSON形式の文字列を指定します。この文字列が有効なJSON形式でない場合、json_decodeはnullを返し、その旨のエラーメッセージが発生します。
第二引数: 結果を配列にするかオブジェクトにするか
第二引数は省略可能で、デフォルトではfalseとして扱われます。trueを指定すると、JSONデータは連想配列として変換され、falseまたは省略した場合は、PHPのオブジェクトとして変換されます。このため、デコード後にデータをどのようにアクセスしたいかによって設定を変更します。
JSON配列のデコード
JSON形式では、配列も表現可能です。例えば、以下のようなJSON配列を考えます:
[
{"name": "John Doe", "age": 30},
{"name": "Jane Smith", "age": 25}
]
このJSON配列をデコードし、PHPの連想配列としてアクセスする例を以下に示します。
$jsonArray = '[{"name": "John Doe", "age": 30}, {"name": "Jane Smith", "age": 25}]';
$array = json_decode($jsonArray, true);
foreach ($array as $person) {
echo "Name: " . $person['name'] . ", Age: " . $person['age'] . "\n";
}
nullになる原因
json_decode が null を返す場合、JSON文字列に問題があります。主な原因と対処法を整理します。
JSON形式が不正
中括弧や角括弧の閉じ忘れ、コロンの欠落などの構文エラーです。
// NG: 閉じ括弧が欠けている
$json = '{"name": "John"';
var_dump(json_decode($json, true)); // NULL
文字コードの問題
json_decode はUTF-8のみを受け付けます。Shift_JISやEUC-JPなどの文字コードが混入すると null になります。
// Shift_JIS文字列が含まれる場合は事前に変換が必要
$json = mb_convert_encoding($sjisJson, 'UTF-8', 'SJIS');
$data = json_decode($json, true);
深さ制限(デフォルト512)
ネストが深すぎる場合は null が返ります。第3引数でフラグ、第4引数で深さを変更できます。
// 深さ上限を1024に拡張
$data = json_decode($json, true, 1024);
末尾カンマ
JSONの仕様では末尾カンマは許可されていません。JavaScriptでは動作することがあるため混入しやすいです。
// NG: 末尾カンマが含まれる
$json = '{"name": "John", "age": 30,}';
var_dump(json_decode($json, true)); // NULL
シングルクォートの使用
JSONの文字列はダブルクォートで囲む必要があります。シングルクォートを使うと無効なJSONになります。
// NG: シングルクォートは無効
$json = "{'name': 'John'}";
var_dump(json_decode($json, true)); // NULL
// OK: ダブルクォートを使う
$json = '{"name": "John"}';
var_dump(json_decode($json, true)); // array(1) { ["name"]=> string(4) "John" }
エラーハンドリング
JSONのデコード中にエラーが発生することもあります。例えば、無効なJSON文字列やエンコードされた部分の不整合などがあげられます。
json_last_error() と json_last_error_msg() の使い方
json_last_error() でエラーコードを、json_last_error_msg() で人が読めるエラーメッセージを取得できます。
$jsonData = '{"name": "John Doe", "age": 30'; // 不完全なJSON
$result = json_decode($jsonData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo 'エラーコード: ' . json_last_error() . "\n";
echo 'エラー内容: ' . json_last_error_msg() . "\n";
// エラーコード: 4
// エラー内容: Syntax error
}
主なエラーコードの一覧です。
| 定数 | 値 | 内容 |
|---|---|---|
JSON_ERROR_NONE |
0 | エラーなし |
JSON_ERROR_DEPTH |
1 | 最大スタック深さを超えた |
JSON_ERROR_STATE_MISMATCH |
2 | 不正またはフォーマット不正なJSON |
JSON_ERROR_CTRL_CHAR |
3 | 制御文字エラー |
JSON_ERROR_SYNTAX |
4 | 構文エラー |
JSON_ERROR_UTF8 |
5 | UTF-8文字でない文字が含まれる |
JSON_THROW_ON_ERROR を使う
PHP 7.3以降では JSON_THROW_ON_ERROR フラグを使うとエラー時に例外 (JsonException) がスローされます。try-catchで処理でき、json_last_error() を都度確認する必要がなくなります。
try {
$data = json_decode('invalid json', true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
echo 'JSONデコード失敗: ' . $e->getMessage(); // Syntax error
}
APIレスポンスを処理するなど、失敗が許容できないケースでは JSON_THROW_ON_ERROR を使うのが推奨です。基礎的なエンコード・デコードの操作例をもう一度おさらいしたい場合は「初心者向け:PHPでJSONデータを簡単に操作する方法と活用事例」も参考になります。
LaravelでJSONを変換する方法
LaravelではPHPの json_decode() を直接使う場面も多いですが、フレームワーク固有の機能を使うことでより簡潔に書けるケースがあります。json_decode() はPHP標準の低レイヤー関数であるのに対し、Laravelは $request->json() やEloquent castなど、アプリケーション向けの抽象化を提供しています。
RequestのJSON取得
クライアントがJSON形式でPOSTリクエストを送ってきた場合、$request->json() または $request->input() で値を取得できます。内部で自動的に json_decode が行われるため、手動で変換する必要はありません。
// Content-Type: application/json のリクエストの場合
public function store(Request $request)
{
$name = $request->input('name'); // 単一フィールドの取得
$data = $request->json()->all(); // 全フィールドを配列で取得
$email = $request->json('user.email'); // ネストしたキーもドット記法で取得可能
}
Eloquent castでJSONカラムを配列にする
モデルの $casts プロパティを使うと、DBに保存したJSON文字列を取得時に自動で配列に変換できます。保存時は逆に配列を自動でJSON文字列に変換してくれるため、手動で json_decode / json_encode を呼ぶ必要がありません。
class User extends Model
{
protected $casts = [
'settings' => 'array', // 取得時に自動でjson_decode、保存時に自動でjson_encode
];
}
// 使用例
$user = User::find(1);
$theme = $user->settings['theme']; // DBのJSON文字列が配列として返る
// 保存時も配列のまま渡せる(自動でJSON文字列に変換される)
$user->settings = ['theme' => 'dark', 'lang' => 'ja'];
$user->save();
注意点: 取得済みの配列の一部だけを書き換えて$user->settings['theme'] = 'dark';のように直接キーを更新しても、Eloquentの変更検知が働かずsave()しても反映されないことがあります。安全に更新するには、いったん配列ごと取得してから書き換え、配列ごと再代入してください。
APIレスポンスとしてJSONを返す
LaravelのコントローラーからクライアントへJSONを返す場合は response()->json() を使います。自動的に Content-Type: application/json ヘッダーが付与されます。
public function index()
{
$users = User::all();
return response()->json([
'data' => $users,
'count' => $users->count(),
]);
}
// HTTPステータスコードを指定する場合
public function store(Request $request)
{
$user = User::create($request->validated());
return response()->json($user, 201);
}
外部APIのレスポンスからJSONを取得する
外部APIのレスポンスを処理する場合は Http ファサードを使うと便利です。json() メソッドで自動的に配列に変換されます。
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/users');
$users = $response->json(); // json_decode($body, true) と同等
foreach ($users as $user) {
echo $user['name'] . "\n";
}
Laravelを使わないプレーンなPHPで外部のJSONファイルを読み込みたい場合は、file_get_contents と組み合わせるのが定番です。取得したJSON文字列をそのまま json_decode に渡すだけで配列に変換できます。詳しい使い方は「file_get_contents — ファイル/URLの内容を文字列で一括取得」で解説しています。
toArray() / toJson() / json_decode() の違い
Laravelでデータを変換する際の主要なメソッドの役割を整理します。
| メソッド | 役割 | 入力 | 出力 | 主な用途 |
|---|---|---|---|---|
json_decode($json, true) |
JSON文字列 → 配列に変換 | JSON文字列 | 配列(array) | 外部APIのレスポンス処理、JSONファイルの読み込み |
$model->toArray() |
Eloquentモデル → 配列に変換 | Eloquentモデル | 配列(array) | レスポンスの整形、テスト、配列操作 |
$model->toJson() |
Eloquentモデル → JSON文字列に変換 | Eloquentモデル | JSON文字列 | JSON文字列として直接出力・保存する場合 |
$user = User::find(1);
// EloquentモデルをPHP配列に変換
$array = $user->toArray();
// ['id' => 1, 'name' => 'Taro', ...]
// EloquentモデルをJSON文字列に変換
$json = $user->toJson();
// '{"id":1,"name":"Taro",...}'
// JSON文字列をPHP配列に変換(PHP標準関数)
$data = json_decode($json, true);
// ['id' => 1, 'name' => 'Taro', ...]
よくある質問
json_decodeとは?
json_decode はPHPの組み込み関数で、JSON形式の文字列をPHPの配列またはオブジェクトに変換します。APIやファイルから受け取ったJSONデータをPHPで扱えるようにするために使います。第2引数に true を指定すると連想配列、省略またはfalseを指定するとstdClassオブジェクトとして返ります。
json_decodeで配列にするには?
第2引数に true を指定します。
$data = json_decode($json, true); // 連想配列として返る
echo $data['key'];
省略した場合はオブジェクトとして返るため、$data->key でアクセスする必要があります。
trueを付ける意味は?
第2引数の true は、JSONオブジェクトをPHPの連想配列として変換するフラグです。false または省略した場合は stdClass オブジェクトとして返ります。
$json = '{"key": "value"}';
$array = json_decode($json, true); // ['key' => 'value']
$object = json_decode($json, false); // stdClass { key: 'value' }
オブジェクトと配列の違いは?
戻り値の型とアクセス方法が異なります。実務では配列(true 指定)を使うことが多いです。
| 項目 | 配列(true指定) | オブジェクト(省略) |
|---|---|---|
| 型 | array |
stdClass |
| アクセス | $data['key'] |
$data->key |
| 配列関数 | array_map、array_filter 等が使える |
使えない(変換が必要) |
| Laravelとの相性 | 良い(collect() 等でそのまま使える) |
変換が必要な場合がある |
nullになる原因は?
json_decode が null を返す主な原因は以下のとおりです。
- JSON文字列の構文エラー(括弧の閉じ忘れ、末尾カンマなど)
- シングルクォートを使用している(JSONはダブルクォートのみ有効)
- UTF-8以外の文字コードが含まれている
- ネストの深さが制限(デフォルト512)を超えている
json_last_error_msg() を呼び出すと具体的なエラー内容を確認できます。
LaravelでJSONを配列に変換するには?
場面によって使う方法が変わります。
- リクエストのJSONを取得する場合:
$request->json()->all()または$request->input('key')を使います。手動でjson_decodeする必要はありません。 - 外部APIのレスポンスを変換する場合:
Http::get(...)->json()で自動的に配列として取得できます。 - JSON文字列を手動で変換する場合:
json_decode($json, true)を使います(第2引数trueが必須)。
// リクエストから
$data = $request->json()->all();
// 外部APIから
$data = Http::get('https://api.example.com/data')->json();
// 文字列から
$data = json_decode($jsonString, true);
EloquentのJSONカラムはどう扱う?
モデルの $casts に 'column_name' => 'array' を定義するのが推奨の方法です。取得時に自動で配列に変換、保存時に自動でJSON文字列に変換されるため、アプリケーションコード上は常にPHP配列として扱えます。
class Product extends Model
{
protected $casts = [
'options' => 'array',
];
}
$product = Product::find(1);
$color = $product->options['color']; // 配列として直接アクセス
$product->options = ['color' => 'red', 'size' => 'L'];
$product->save(); // 自動的にJSON文字列として保存される
toArrayとtoJsonの違いは?
toArray() はEloquentモデルをPHP配列に変換します。配列操作や他のLaravel機能(collect() など)と組み合わせて使いたい場合に向いています。toJson() はモデルをJSON文字列に変換します。APIレスポンスとして文字列出力が必要な場合や、ファイルへの書き込みに向いています。なお response()->json($model) とすれば内部で自動的に変換されるため、どちらも明示的に呼ぶ必要はありません。
$user = User::find(1);
$user->toArray(); // PHP配列 → collect() や array_map() でそのまま使える
$user->toJson(); // JSON文字列 → そのまま出力・保存できる
// APIレスポンスでは response()->json() に渡すだけでOK
return response()->json($user); // 内部で toArray() → json_encode が行われる
まとめ
json_decode関数は、PHPでJSONを扱う上で非常に重要です。第2引数で配列・オブジェクトを使い分け、json_last_error() や JSON_THROW_ON_ERROR でエラーを適切にハンドリングしましょう。Laravelを使っている場合は、場面に応じてフレームワーク機能を使い分けるのがポイントです。リクエストのJSONには $request->json()、DBのJSONカラムにはEloquent castの 'array'、レスポンスには response()->json()、外部APIには Http::get()->json() を使うと、json_decode を直接呼ぶより簡潔で安全なコードになります。toArray() はモデルをPHP配列に変換し、toJson() はJSON文字列に変換します。この使い分けを覚えておくと、LaravelでのJSON変換に迷うことがなくなります。

コメント