Question
I need an efficient way to check whether a string contains valid JSON in PHP. Right now I am using this approach, but I suspect it is not ideal:
function isJson($string) {
return is_string($string) &&
(is_object(json_decode($string)) || is_array(json_decode($string)));
}
Is there a faster or better way to validate whether a string is JSON? I am especially interested in correctness and performance.
Short Answer
By the end of this page, you will understand how JSON validation works in PHP, why calling json_decode() multiple times is wasteful, and how to correctly check JSON using json_last_error() or exceptions. You will also see practical examples, common mistakes, and a small project that turns this idea into reusable validation code.
Concept
JSON validation in PHP is usually done by trying to decode the string and then checking whether decoding succeeded.
The key idea is:
- PHP does not provide a separate "is this JSON?" parser that is faster than decoding.
- In practice, you validate JSON by calling
json_decode(). - After decoding, you inspect whether an error occurred.
A common beginner mistake is to decide based on the decoded value's type, such as checking is_object() or is_array(). That seems reasonable at first, but valid JSON is not limited to objects and arrays.
These are all valid JSON values:
{"name":"Ada"}
[1, 2, 3]
"hello"
123
true
null
That means a function that only accepts arrays or objects will incorrectly reject valid JSON like "hello", 123, true, or null.
Why this matters in real programming:
- APIs often send JSON objects or arrays, but not always.
- Configuration values may contain JSON scalars.
- Webhooks, logs, queues, and external integrations may produce malformed JSON.
- Efficient validation matters when processing many records.
So the best approach is usually:
- Decode once.
- Check for errors.
- Return the result.
This is both more correct and more efficient than decoding multiple times.
Mental Model
Think of json_decode() like a language translator.
- You hand it a string.
- It tries to translate that string from JSON into a PHP value.
- If translation succeeds, the JSON was valid.
- If translation fails, PHP records the reason.
The important part is that you do not ask, "Did I get an object or array?" Instead, you ask, "Did the translator report an error?"
That mental model helps because JSON can translate into many different PHP value types, not just arrays and objects.
Syntax and Examples
The standard pattern in PHP is:
function isJson(string $string): bool
{
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
Example
var_dump(isJson('{"name":"Ada"}')); // true
var_dump(isJson('[1,2,3]')); // true
var_dump(isJson('"hello"')); // true
var_dump(isJson('123')); // true
var_dump(isJson('not json')); // false
Why this is better
json_decode()is called only once.- It works for all valid JSON values.
- It uses PHP's built-in error reporting for JSON parsing.
If you only want JSON objects or arrays
Sometimes your app specifically expects a JSON object or array, not just any valid JSON.
function isJsonObjectOrArray(string $string): bool
{
$decoded = json_decode($string, true);
return json_last_error() === JSON_ERROR_NONE && is_array($decoded);
}
This works because:
- With
true, objects become associative arrays. - JSON arrays also become PHP arrays.
- Scalars like strings, numbers, booleans, and
nullwill not pass.
Use this version only if your requirement is stricter than "valid JSON."
Step by Step Execution
Consider this function:
function isJson(string $string): bool
{
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
Now trace this input:
$input = '{"active":true}';
$result = isJson($input);
Step by step
$inputstores the string{"active":true}.isJson($input)is called.- Inside the function,
json_decode($string)tries to parse the string. - PHP successfully understands the JSON.
json_last_error()returnsJSON_ERROR_NONE.- The comparison becomes
true. - The function returns
true.
Now with invalid input:
$input = '{active:true}';
$result = isJson($input);
What changes
json_decode()tries to parse the string.- JSON requires quoted keys, so
{active:true}is invalid. - PHP records a JSON parsing error.
json_last_error()is no longerJSON_ERROR_NONE.- The function returns
false.
Important detail
This input is valid JSON:
$input = 'null';
json_decode('null')returnsnull.- That does not mean parsing failed.
- You must check
json_last_error()to know whether it was valid.
That is why checking only the decoded value can be misleading.
Real World Use Cases
Here are common situations where JSON validation appears in real PHP applications:
API request handling
A server receives JSON in a request body and must reject malformed payloads.
$body = file_get_contents('php://input');
if (!isJson($body)) {
http_response_code(400);
echo 'Invalid JSON';
exit;
}
Reading configuration from a file
$configText = file_get_contents('config.json');
if (!isJson($configText)) {
die('Configuration file is not valid JSON');
}
Importing queue messages
Workers often consume JSON messages from queues such as Redis, RabbitMQ, or SQS.
$message = '{"task":"resize-image","id":42}';
if (isJson($message)) {
$data = json_decode($message, true);
}
Validating third-party responses
External services may sometimes return HTML error pages instead of JSON.
$response = $client->getBody();
if (!isJson($response)) {
throw new RuntimeException('Expected JSON response');
}
Real Codebase Usage
In real projects, developers usually do more than just "check if it is JSON."
Decode once and keep the result
If you need the decoded data, avoid decoding once for validation and again for usage.
$data = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidArgumentException('Invalid JSON: ' . json_last_error_msg());
}
This pattern is better because parsing happens only once.
Guard clauses
A common pattern is to fail early when input is invalid.
$data = json_decode($payload, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return ['error' => 'Invalid JSON'];
}
Validation after decoding
Valid JSON does not mean valid business data.
$data = json_decode($payload, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidArgumentException('Invalid JSON');
}
if (!isset($data['email'])) {
throw new InvalidArgumentException('Missing email field');
}
Using exceptions in modern PHP
PHP supports JSON_THROW_ON_ERROR, which can make code cleaner.
function decodeJson(string $json): array
{
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
Then use it like this:
try {
$data = decodeJson('{"name":"Ada"}');
} catch (JsonException $e) {
echo 'Invalid JSON: ' . $e->getMessage();
}
This is common in modern codebases because it avoids manually checking json_last_error() after every decode.
Common Mistakes
1. Decoding multiple times
Broken approach:
function isJson($string) {
return is_object(json_decode($string)) || is_array(json_decode($string));
}
Problem:
json_decode()runs twice.- Parsing JSON is the expensive part.
- Repeating it wastes time.
Fix:
function isJson(string $string): bool
{
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
2. Assuming valid JSON must be an object or array
Broken assumption:
var_dump(isJson('123')); // should be true for valid JSON
var_dump(isJson('"text"')); // should be true for valid JSON
Problem:
- JSON supports scalar values too.
Fix:
- Decide whether you want valid JSON or specifically a JSON object/array.
3. Using the decoded result alone to detect errors
Broken code:
$result = json_decode('null');
if ($result === null) {
echo 'Invalid JSON';
}
Problem:
'null'is valid JSON.json_decode('null')returnsnulleven when parsing succeeds.
Fix:
json_decode('null');
if (json_last_error() === JSON_ERROR_NONE) {
echo 'Valid JSON';
}
4. Forgetting type expectations
If your application expects an array but the input is valid JSON string data, validation may pass but later logic may fail.
$data = json_decode('"hello"', true);
// This will be a problem if you expected an array
Fix:
- Validate JSON first.
- Then validate the expected structure.
5. Ignoring error messages
When debugging bad payloads, use json_last_error_msg().
json_decode($input);
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_last_error_msg();
}
This makes issues much easier to diagnose.
Comparisons
| Approach | What it checks | Correct for all valid JSON? | Performance | Best use case |
|---|---|---|---|---|
| `is_object(json_decode(...)) | is_array(json_decode(...))` | Whether decoded result is object or array | No | |
json_decode(...); json_last_error() === JSON_ERROR_NONE | Whether parsing succeeded | Yes | Good | General JSON validation |
json_decode(..., true); is_array($decoded) | Whether JSON is object/array-like data | No, only for structured JSON | Good | APIs expecting objects or arrays |
json_decode(..., true, 512, JSON_THROW_ON_ERROR) | Whether parsing succeeded, via exception | Yes | Good | Modern PHP codebases |
json_last_error() vs JSON_THROW_ON_ERROR
| Option | Style | Pros | Cons |
|---|---|---|---|
json_last_error() | Manual checking | Simple, widely used | Easy to forget error checks |
JSON_THROW_ON_ERROR | Exception-based | Cleaner in larger apps | Requires exception handling |
Validation vs structure checking
- Validation asks: "Is this valid JSON?"
- Structure checking asks: "Is this the kind of JSON my app expects?"
Those are related, but not the same.
Cheat Sheet
// Check if a string is valid JSON
function isJson(string $string): bool
{
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
// Decode and throw on invalid JSON
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
Rules to remember
json_decode()is the normal way to validate JSON in PHP.- Call it once if possible.
- Use
json_last_error()orJSON_THROW_ON_ERROR. - Valid JSON can be:
- object
- array
- string
- number
- boolean
null
- Do not assume only arrays or objects are valid.
json_decode('null')returnsnull, but it is still valid JSON.
Useful helpers
json_last_error()
json_last_error_msg()
Common pattern when you need decoded data
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidArgumentException(json_last_error_msg());
}
Edge case
An empty string is not valid JSON:
isJson(''); // false
A quoted string is valid JSON:
isJson('"hello"'); // true
FAQ
Is json_decode() the fastest way to check JSON in PHP?
Yes, in practice this is the standard and efficient way. PHP validates JSON by parsing it, so decoding is the normal approach.
Why is calling json_decode() twice a problem?
Because parsing happens twice. That adds unnecessary work and gives no benefit.
Why does checking is_array() or is_object() reject some valid JSON?
Because valid JSON can also be a string, number, boolean, or null, not just an object or array.
How do I get the reason JSON parsing failed?
Use json_last_error_msg() after json_decode().
Should I use json_last_error() or JSON_THROW_ON_ERROR?
For simple scripts, json_last_error() is fine. For modern applications, JSON_THROW_ON_ERROR is often cleaner.
Is null valid JSON in PHP?
Yes. The string null is valid JSON.
How can I check that JSON is specifically an object or array?
Decode it and then verify the resulting PHP value matches the structure you expect, usually with is_array() when using associative decoding.
Should I validate JSON separately and then decode it?
Usually no. Decode once, check for errors, and reuse the decoded result.
Mini Project
Description
Build a small PHP utility that validates incoming JSON payloads and returns either decoded data or a readable error message. This mirrors a common backend task when handling API requests, webhooks, or configuration files.
Goal
Create a reusable JSON parser that detects invalid JSON and safely returns decoded PHP data.
Requirements
- Write a function that accepts a JSON string.
- Decode the JSON only once.
- Return a success result with decoded data when the JSON is valid.
- Return an error result with a helpful message when the JSON is invalid.
- Demonstrate the function with both valid and invalid examples.
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.