◀ 2.

Cannot use object of type stdClass as array エラーの対処

▶
この記事の要点
  • 原因は stdClass オブジェクトに配列の書き方 $obj['key'] でアクセスしていること
  • 最短の対処はアロー演算子 $obj->key に書き換える
  • JSON 由来なら json_decode($json, true) で最初から連想配列にするのが確実
  • Laravel のクエリビルダ(DB::table())や PDO の FETCH_OBJ も stdClass を返すので要注意
  • (array)$obj は 1 階層だけ変換。ネストしたデータは丸ごと変換が必要

エラー内容

PHP 7 以降では、次のような Fatal error が出て処理が止まります。

Fatal error: Uncaught Error: Cannot use object of type stdClass as array in /path/to/file.php:12

メッセージを直訳すると「stdClass 型のオブジェクトを配列として使うことはできません」です。末尾のファイル名と行番号が、問題のアクセスをしている箇所です。

原因:オブジェクトに配列の書き方でアクセスしている

stdClass は PHP の汎用的な空のクラスで、プロパティを自由に追加できる「入れ物」です。見た目は連想配列に似ていますが、型としてはオブジェクトなので、要素の取り出し方が違います。

データの型正しいアクセス間違ったアクセス(エラーになる)
連想配列(array)$data['name']$data->name
オブジェクト(stdClass)$data->name$data['name']

つまり、$配列[インデックス] という扱いではなく、$stdClass->インデックス という扱いにすれば解決できます。

stdClass が返ってくる代表的な場面

自分で new stdClass() を書いた覚えがなくても、次のような関数・ライブラリが stdClass を返します。

  • json_decode($json): 第 2 引数を省略すると、JSON のオブジェクトは stdClass になる(最も多い原因)
  • PDO: fetch(PDO::FETCH_OBJ) / fetchAll(PDO::FETCH_OBJ) で取得した行
  • Laravel のクエリビルダ: DB::table('users')->get() や ->first() の各行は stdClass(Eloquent モデルとは別物)
  • (object)$array: 配列をオブジェクトにキャストした結果
  • 外部 API の SDK など、レスポンスをオブジェクトで返すライブラリ

対処法

1. アロー演算子でアクセスする(基本)

$json = '{"name":"Taro","address":{"city":"Tokyo"}}';
$user = json_decode($json);

// NG: Cannot use object of type stdClass as array
// echo $user['name'];

// OK
echo $user->name;            // Taro
echo $user->address->city;   // Tokyo

キー名にハイフンなど識別子に使えない文字が含まれる場合は、波かっこで囲みます。

$obj = json_decode('{"first-name":"Taro"}');
echo $obj->{'first-name'};   // Taro

2. json_decode で最初から連想配列にする

配列として扱うコードがすでに多い場合は、デコード側を変えるのが一番影響が少なく済みます。

$user = json_decode($json, true);   // 第 2 引数 true で連想配列
echo $user['name'];
echo $user['address']['city'];

// フラグで指定する書き方でも同じ
$user = json_decode($json, null, 512, JSON_OBJECT_AS_ARRAY);

3. 取得済みのオブジェクトを配列に変換する

// 1 階層だけ変換(ネストした中身は stdClass のまま)
$arr = (array)$user;
$arr2 = get_object_vars($user);

// ネストも含めて丸ごと変換
$deep = json_decode(json_encode($user), true);

(array) キャストは外側だけが配列になるため、$arr['address']['city'] と書くと、内側で同じエラーが再発します。ネストしている場合は json_encode → json_decode(..., true) の往復が簡単です。

4. PDO・Laravel の場合

// PDO: 連想配列で受け取る
$rows = $pdo->query('SELECT id, name FROM users')->fetchAll(PDO::FETCH_ASSOC);
echo $rows[0]['name'];

// Laravel クエリビルダ: 各行は stdClass なのでアローで読む
$users = DB::table('users')->get();
foreach ($users as $u) {
    echo $u->name;
}

// どうしても配列が欲しい場合
$array = DB::table('users')->get()
    ->map(fn ($row) => (array)$row)
    ->all();

Eloquent モデル(User::find(1) など)は ArrayAccess を実装しているため $user['name'] でも読めますが、クエリビルダの結果は読めません。同じプロジェクト内で両方を使っていると混乱しやすいポイントです。

落とし穴

  • 逆のエラー: 配列にアロー演算子を使うと、PHP 8 では「Attempt to read property "name" on array」という警告が出て値は null になります(PHP 7 では「Trying to get property of non-object」の Notice)。どちらの型かを確認してから書き換えましょう
  • Blade やテンプレート内でも同じ: {{ $item['name'] }} でエラーが出る場合、コントローラから渡しているのが stdClass の可能性があります
  • null の可能性: JSON が不正だと json_decode は null を返します。PHP 8 なら $user?->address?->city のような nullsafe 演算子で安全に読めます
  • 配列関数に渡せない: array_column などはオブジェクトの配列にも一部対応しますが、array_merge などは配列前提です。配列関数を多用するなら最初から連想配列で受け取る方が楽です

確認方法

変数の型が分からないときは、まず中身を表示して確認します。

var_dump($user);
// object(stdClass)#1 (2) { ... } と出たらオブジェクト
// array(2) { ... } と出たら配列

var_dump(is_object($user), is_array($user));
echo get_debug_type($user);   // PHP 8: "stdClass" や "array"

Laravel なら dd($user) でも型が表示されます。表示結果が object(stdClass) ならアロー演算子、array なら角かっこ、と書き分けてください。

関連

Post Share
子ページ

子ページはありません

同階層のページ
  1. Fatal error: Maximum execution time of 30 seconds exceeded in...
  2. Fatal error: Uncaught Error: Cannot use object of type stdClass as array in ...
  3. Warning: Use of undefined constant ... - assumed '...' (this will throw an Error)
  4. ERROR: Call to undefined method Maatwebsite\Excel\Excel::load()
  5. Maximum execution time of 30 seconds exceeded
  6. Your requirements could not be resolved to an installable set of packages. ... To enable extensions, verify that they are enabled in your .ini files:
  7. could not find driver
  8. the requested PHP extension mbstring is missing from your system.
  9. the requested PHP extension dom is missing from your system.
  10. A non well formed numeric value encountered
  11. Warning: Cannot modify header information - headers already sent by ...
  12. php_network_getaddresses: getaddrinfo failed: Name or service not known
  13. XMLWriter::openUri(): Unable to resolve file path
  14. Object of class stdClass could not be converted to string
  15. Class 'Google_Service_Youtube' not found