Common causes
- json_decode($json) without the second argument returns stdClass objects, not arrays
- Database results fetched as objects ($wpdb->get_results() default OBJECT, PDO::FETCH_OBJ, mysqli fetch_object())
- WordPress functions returning objects such as WP_Post, WP_User or WP_Term
- API client libraries returning response objects
- Mixing code written for arrays with a library that changed to returning objects
How to fix it
- Check what the variable is. var_dump($data) or get_debug_type($data) to confirm it is an object and see its property names.
- Use object syntax. Change $data['name'] to $data->name, and nested $data['user']['email'] to $data->user->email.
- Decode JSON as arrays. If the rest of the code expects arrays, use json_decode($json, true) so you get associative arrays throughout.
- Choose the fetch mode. WordPress: $wpdb->get_results($sql, ARRAY_A). PDO: $stmt->fetch(PDO::FETCH_ASSOC). mysqli: fetch_assoc() instead of fetch_object().
- Convert only when needed. (array) $obj works for flat stdClass objects; for nested ones use json_decode(json_encode($obj), true). Avoid this on large data in hot paths.
- For framework objects, use their API. Laravel collections support ->toArray(), ->get('key') and array access on some types; Eloquent models expose attributes via ->name or ->toArray().
PHP
$obj = json_decode($json); // stdClass
echo $obj->user->email;
$arr = json_decode($json, true); // array
echo $arr['user']['email'];
$rows = $wpdb->get_results($sql, ARRAY_A); // WordPress How to stop it happening again
- Pick arrays or objects for a dataset and stick to it
- Always pass true to json_decode() when you want arrays
- Set the database fetch mode explicitly