Question

How to Check If a String Is Valid JSON in PHP

phpjson

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:

  1. Decode once.
  2. Check for errors.
  3. 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.

Take Quiz

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 null will 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

  1. $input stores the string {"active":true}.
  2. isJson($input) is called.
  3. Inside the function, json_decode($string) tries to parse the string.
  4. PHP successfully understands the JSON.
  5. json_last_error() returns JSON_ERROR_NONE.
  6. The comparison becomes true.
  7. The function returns true.

Now with invalid input:

$input = '{active:true}';
$result = isJson($input);

What changes

  1. json_decode() tries to parse the string.
  2. JSON requires quoted keys, so {active:true} is invalid.
  3. PHP records a JSON parsing error.
  4. json_last_error() is no longer JSON_ERROR_NONE.
  5. The function returns false.

Important detail

This input is valid JSON:

$input = 'null';
  • json_decode('null') returns null.
  • 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');
}
Take Quiz

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') returns null even 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

ApproachWhat it checksCorrect for all valid JSON?PerformanceBest use case
`is_object(json_decode(...))is_array(json_decode(...))`Whether decoded result is object or arrayNo
json_decode(...); json_last_error() === JSON_ERROR_NONEWhether parsing succeededYesGoodGeneral JSON validation
json_decode(..., true); is_array($decoded)Whether JSON is object/array-like dataNo, only for structured JSONGoodAPIs expecting objects or arrays
json_decode(..., true, 512, JSON_THROW_ON_ERROR)Whether parsing succeeded, via exceptionYesGoodModern PHP codebases

json_last_error() vs JSON_THROW_ON_ERROR

OptionStyleProsCons
json_last_error()Manual checkingSimple, widely usedEasy to forget error checks
JSON_THROW_ON_ERRORException-basedCleaner in larger appsRequires 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.

Take Quiz

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() or JSON_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') returns null, 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.

Take Quiz

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.
Take Quiz

Keep learning

Related questions

View more