Question
How can I parse this JSON file in PHP and loop through its unknown top-level names and nested fields?
{
"John": {
"status": "Wait"
},
"Jennifer": {
"status": "Active"
},
"James": {
"status": "Active",
"age": 56,
"count": 10,
"progress": 0.0029857,
"bad": 0
}
}
I can access known values like this:
<?php
$string = file_get_contents('/home/michael/test.json');
$json_a = json_decode($string, true);
echo $json_a['John']['status'];
echo $json_a['Jennifer']['status'];
However, I do not know the names (John, Jennifer, and so on) or every nested key (age, count, and so on) in advance. How can I use foreach to iterate through all names, keys, and values?
Short Answer
You will learn how PHP represents decoded JSON, how to choose arrays or objects with json_decode(), and how nested foreach loops handle JSON with dynamic keys. You will also learn how to safely read optional fields such as age when they may not exist for every record.
Concept
JSON objects contain named properties. In the example, the outer JSON object has dynamic property names such as John, Jennifer, and James. Each name points to another JSON object containing details.
When you call json_decode($json, true), PHP converts JSON objects into associative arrays:
$data = json_decode($json, true);
The resulting shape is conceptually:
[
'John' => ['status' => 'Wait'],
'Jennifer' => ['status' => 'Active'],
'James' => [
'status' => 'Active',
'age' => 56,
'count' => 10,
'progress' => 0.0029857,
'bad' => 0,
],
]
An associative array stores values under keys, rather than only numeric positions. foreach is useful because it gives you both the current key and its value without knowing the keys beforehand.
Mental Model
Think of the decoded JSON as a filing cabinet.
- The outer cabinet has drawers labelled
John,Jennifer, andJames. - Each drawer contains a folder of labelled facts, such as
status,age, andcount. - You do not need to know every drawer label first:
foreachopens each drawer in turn. - A second
foreachreads every labelled fact inside that drawer.
The variable before => receives the label (key), and the variable after => receives what is stored under that label (value).
Syntax and Examples
Use json_decode() with true when you want associative arrays, then use nested foreach loops.
<?php
$json = file_get_contents('/home/michael/test.json');
$people = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
foreach ($people as $name => $details) {
echo "$name\n";
foreach ($details as $field => $value) {
echo " $field: $value\n";
}
}
Possible output:
John
status: Wait
Jennifer
status: Active
James
status: Active
age: 56
count: 10
progress: 0.0029857
bad: 0
The outer loop assigns:
$name: a dynamic top-level key, such asJames
Step by Step Execution
Consider this smaller JSON document:
$json = '{
"John": {"status": "Wait"},
"James": {"status": "Active", "age": 56}
}';
$people = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
foreach ($people as $name => $details) {
echo "$name\n";
foreach ($details as $field => $value) {
echo "$field = $value\n";
}
}
Execution trace:
json_decode(..., true)converts the outer JSON object into an associative array.- On the first outer-loop iteration,
$nameisJohnand$detailsis['status' => 'Wait']. - The inner loop runs once:
$fieldisstatusand is .
Real World Use Cases
Dynamic JSON keys appear in many practical situations:
- Configuration files: Feature flags may be grouped by an unknown environment or service name.
- API responses: A reporting API may return account IDs as object keys, with metrics inside each account.
- Import scripts: A JSON export may use product SKUs, usernames, or dates as keys.
- Monitoring data: Server names can be keys, while CPU, memory, and status values are nested fields.
- Translation files: Language codes such as
en,fr, anddecan map to nested message collections.
For example, an API might return server health by host name:
foreach ($servers as $hostname => $metrics) {
$cpu = $metrics['cpu'] ?? null;
echo "$hostname uses $cpu% CPU\n";
}
Real Codebase Usage
In production PHP code, developers usually combine iteration with validation and safe access.
Validate file and JSON input
<?php
$path = '/home/michael/test.json';
if (!is_readable($path)) {
throw new RuntimeException("Cannot read JSON file: $path");
}
$contents = file_get_contents($path);
$people = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($people)) {
throw new UnexpectedValueException('Expected the JSON root to be an object.');
}
JSON_THROW_ON_ERROR makes invalid JSON fail immediately with a JsonException, instead of silently returning null.
Use guard clauses for unexpected records
External data can be incomplete or malformed. Skip entries that do not have the expected array structure.
Common Mistakes
Leaving array keys unquoted
This is incorrect:
// Broken: status is treated as a constant in older PHP versions.
echo $json_a['John'][status];
Use quotes for string keys:
echo $json_a['John']['status'];
Assuming every field exists
John does not have an age field. This can produce an undefined array key warning:
// Broken for people without an age.
echo $details['age'];
Use a fallback or check for the key:
echo $details['age'] ?? 'Not provided';
Using object syntax after decoding into arrays
With the second argument set to true, the result uses arrays. This is incorrect:
Comparisons
| Approach | json_decode() call | Access syntax | Best when |
|---|---|---|---|
| Associative arrays | json_decode($json, true) | $person['status'] | You want array functions and clear dynamic-key iteration. |
| PHP objects | json_decode($json) | $person->status | Property names are known and valid PHP property names. |
Nested foreach | One loop per nesting level | foreach ($items as $key => $value) | You need every dynamic key and nested value. |
| Direct access | $people['John']['status'] |
Cheat Sheet
// Decode a JSON object into associative arrays
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
// Loop through dynamic top-level keys
foreach ($data as $key => $value) {
// $key: for example, "James"
// $value: nested array
}
// Loop through nested dynamic keys
foreach ($data as $name => $details) {
foreach ($details as $field => $value) {
echo "$name - $field: $value\n";
}
}
// Safely read an optional field
$status = $details['status'] ?? 'Unknown';
// Check a field explicitly
if (array_key_exists('age', $details)) {
echo $details['age'];
}
FAQ
How do I loop through unknown JSON keys in PHP?
Decode the JSON into an associative array and use foreach ($data as $key => $value). The $key variable receives each unknown property name.
Why does json_decode($json, true) use square brackets?
The true argument tells PHP to convert JSON objects to associative arrays. PHP arrays use square-bracket access, such as $person['status'].
How do I access a nested JSON value in PHP?
For known keys, use nested array access: $data['James']['status']. For unknown keys, iterate with nested foreach loops.
What happens if a JSON field is missing?
Direct access can raise an undefined array key warning. Use $details['age'] ?? null or another appropriate default value.
Should I use json_last_error() or JSON_THROW_ON_ERROR?
For modern PHP, JSON_THROW_ON_ERROR is usually clearer because malformed JSON raises a JsonException at the decoding line.
Can I decode JSON into objects instead of arrays?
Yes. Omit the argument and use object access such as . Do not mix object access with array access.
Mini Project
Description
Build a small PHP command-line report that reads a people-status JSON file. The file uses unknown names as keys, and each person may contain different fields. The report demonstrates decoding JSON, iterating dynamic keys, and safely reading optional values.
Goal
Print one readable summary line for every person and calculate how many people have an Active status.
Requirements
- Read JSON from a file named
people.json. - Decode the JSON as associative arrays.
- Print each person's name and status.
- Print age when it is available.
- Treat a missing status as
Unknown. - Display the total number of active people.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.