【PHP8.x】json_validate関数の使い方

作成日: 更新日:

json_validate関数は、与えられた文字列が有効なJSON形式であるかどうかを検証する関数です。この関数は、JSON文字列を解析し、エラーが発生しなければtrueを、エラーが発生すればfalseを返します。JSON (JavaScript Object Notation) は、データを構造化して表現するための軽量な形式であり、主にウェブアプリケーションやAPIにおいてデータの交換に用いられます。json_validate関数を使用することで、受信したデータや生成されたデータが正しいJSON形式であるかを事前に確認し、エラーを未然に防ぐことができます。

この関数は、PHP 8.3で導入され、それ以前のバージョンでは利用できません。JSONデータの検証は、データの整合性を保つ上で非常に重要です。例えば、APIから受信したデータが期待される形式と異なると、アプリケーションの動作に予期せぬ影響を及ぼす可能性があります。json_validate関数を使用することで、このような問題を早期に検出し、適切なエラー処理を行うことができます。

具体的には、json_validate関数は、入力された文字列をJSONとして解釈できるかどうかを判断します。解釈可能であればtrueを返し、構文エラーやその他の理由で解釈できない場合はfalseを返します。この関数は、JSONデータのデコード処理を行う前に、データの有効性を確認するために使用されることが一般的です。デコード処理 (json_decode関数など) は、無効なJSONデータに対して実行するとエラーが発生する可能性があるため、事前にjson_validate関数で検証することで、より安定したアプリケーションを開発できます。

基本的な使い方

構文(syntax)

json_validate(string $json, int $depth = 512, int $flags = 0): bool

引数(parameters)

string $json, int $depth = 512, int $flags = 0

  • string $json: 検証するJSON文字列
  • int $depth = 512: 再帰の深さの上限
  • int $flags = 0: オプションフラグ

戻り値(return)

bool

JSON文字列が有効なJSON形式である場合にtrueを、そうでない場合にfalseを返します。

サンプルコード

PHP 8.4 json_validate を使ったJSONスキーマ検証

<?php

/**
 * JSON文字列の構文と、簡易的なスキーマ(必須キーの存在)を検証します。
 *
 * この関数は、まず `json_validate()` を用いてJSON文字列の構文が
 * 正しい(well-formed)かを高速にチェックします。
 * その後、指定された必須キーがJSONオブジェクトにすべて存在するかを
 * 検証することで、簡易的なスキーマチェックを行います。
 *
 * より複雑な型チェックやパターン検証など、本格的なJSON Schema仕様に
 * 基づく検証が必要な場合は、専用のライブラリの使用を検討してください。
 *
 * @param string $json   検証対象のJSON文字列。
 * @param array  $schema 検証する必須キーのリスト。例: ['id', 'name']
 * @return bool JSONが構文的に正しく、かつスキーマを満たす場合は true、それ以外は false。
 */
function validateJsonAndSchema(string $json, array $schema): bool
{
    // 手順1: `json_validate()` でJSONの構文が正しいかをチェックします。
    // これにより、不正な形式のJSONを効率的に弾くことができます。
    if (!json_validate($json)) {
        return false;
    }

    // 手順2: 構文が正しいことを確認後、JSONをPHPの連想配列にデコードします。
    // エラー時に例外をスローするフラグを指定しています。
    try {
        $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        // json_validate()を通過していれば通常ここには到達しません。
        return false;
    }
    
    // 手順3: 簡易的なスキーマ検証として、必須キーがすべて存在するかをチェックします。
    foreach ($schema as $requiredKey) {
        if (!array_key_exists($requiredKey, $data)) {
            // 必須キーが一つでも欠けていれば検証失敗とします。
            return false;
        }
    }

    // すべての検証を通過した場合のみ true を返します。
    return true;
}

// --- 以下、サンプルコードの実行例 ---

// 検証に用いるスキーマ(ユーザー情報として 'id' と 'name' を必須とする)
$userSchema = ['id', 'name', 'email'];

// ケース1: 構文も正しく、スキーマも満たすJSON
$validJson = '{"id": 1, "name": "Taro Yamada", "email": "taro@example.com", "age": 30}';
echo "ケース1(正常): " . (validateJsonAndSchema($validJson, $userSchema) ? 'OK' : 'NG') . PHP_EOL;

// ケース2: 構文は正しいが、スキーマを満たさないJSON('email' キーが欠落)
$missingKeyJson = '{"id": 2, "name": "Jiro Suzuki"}';
echo "ケース2(スキーマ不適合): " . (validateJsonAndSchema($missingKeyJson, $userSchema) ? 'OK' : 'NG') . PHP_EOL;

// ケース3: 構文が不正なJSON(末尾に余分なカンマ)
$invalidSyntaxJson = '{"id": 3, "name": "Saburo Tanaka", "email": "saburo@example.com",}';
echo "ケース3(構文エラー): " . (validateJsonAndSchema($invalidSyntaxJson, $userSchema) ? 'OK' : 'NG') . PHP_EOL;

?>

このサンプルコードは、PHPのjson_validate関数を使用して、JSON文字列の妥当性を検証する方法を示しています。json_validateは、第一引数で受け取った文字列がJSONとして正しい構文であるかをチェックし、結果をbool値(真偽値)で返します。正しい場合はtrue、不正な場合はfalseとなります。この関数は、実際にJSONをデコードしてPHPのデータに変換するjson_decodeよりも高速に動作するため、構文チェックのみを目的とする場合に効率的です。

コード内のvalidateJsonAndSchema関数は、二段階の検証を行います。まず、引数$jsonで受け取った文字列をjson_validateで検証し、構文が不正であれば即座にfalseを返します。構文が正しい場合、次にjson_decodeでPHPの連想配列に変換します。その後、第二引数$schemaで指定された必須キーのリストを元に、変換後のデータに必要なキーがすべて存在するかをarray_key_existsで一つずつ確認します。構文が正しく、かつ必須キーがすべて揃っている場合にのみ、この関数は最終的にtrueを返します。これにより、JSONデータの形式と構造の両方を簡易的に検証できます。

json_validate()関数はJSONの構文、つまり文法が正しいかだけを高速にチェックします。この関数だけでは、データの中身(例えば、必須キーの有無や値の型)までは検証できません。サンプルコードの後半で行っているキーの存在チェックは、あくまで簡易的なスキーマ検証です。そのため、キーはあっても値が空だったり、期待と違う型(数値のはずが文字列など)だったりした場合は検出できない点に注意が必要です。また、json_decode()関数の第二引数にtrueを指定して連想配列に変換しないと、その後のキー存在チェックが正しく動作しません。なお、このjson_validate()関数はPHP 8.3以降で利用可能です。

PHPでJSONをスキーマ検証する

<?php

/**
 * JSON文字列が、指定されたスキーマ(構造定義)に適合するかを検証します。
 *
 * この関数は2段階の検証を行います。
 * 1. json_validate() を使用して、文字列が構文的に有効なJSONであるかを確認します。
 * 2. JSONをデコードし、必須キーの存在と各キーの値のデータ型がスキーマ定義と一致するかを確認します。
 *
 * @param string $jsonString 検証対象のJSON文字列
 * @param array $schema 検証ルールを定義したスキーマ配列。例: ['name' => 'string', 'age' => 'integer']
 * @return bool JSONがスキーマに適合する場合にtrue、そうでない場合にfalseを返します。
 */
function validateJsonAgainstSchema(string $jsonString, array $schema): bool
{
    // ステップ1: JSONの構文が正しいか検証する (PHP 8.3以降で利用可能)
    if (!json_validate($jsonString)) {
        // 構文的に無効なJSON
        return false;
    }

    // JSON文字列をPHPの連想配列に変換
    $data = json_decode($jsonString, true);

    // ステップ2: スキーマに基づいて構造と型を検証する
    foreach ($schema as $key => $expectedType) {
        // キーが存在するかチェック
        if (!array_key_exists($key, $data)) {
            return false; // 必須キーが不足している
        }

        // キーに対応する値を取得
        $value = $data[$key];

        // 期待されるデータ型と実際のデータ型が一致するかチェック
        $actualType = gettype($value);
        $isValidType = match ($expectedType) {
            'string' => $actualType === 'string',
            'integer' => $actualType === 'integer',
            'double' => $actualType === 'double', // float型も含む
            'boolean' => $actualType === 'boolean',
            'array' => $actualType === 'array',
            'object' => $actualType === 'object',
            'null' => $actualType === 'NULL',
            default => false,
        };

        if (!$isValidType) {
            return false; // データ型が一致しない
        }
    }

    return true; // 全ての検証をパス
}

// 検証ルールとなるスキーマを定義
// 'id'は整数、'name'は文字列、'isActive'は真偽値であることを期待
$userSchema = [
    'id' => 'integer',
    'name' => 'string',
    'isActive' => 'boolean',
];

// --- 検証の実行例 ---

// 1. 成功例: スキーマに完全に適合するJSON
$validJson = '{"id": 1, "name": "Alice", "isActive": true}';
echo "Valid JSON: ";
var_dump(validateJsonAgainstSchema($validJson, $userSchema)); // bool(true)

// 2. 失敗例: キーが不足しているJSON ('isActive'がない)
$missingKeyJson = '{"id": 2, "name": "Bob"}';
echo "Missing Key JSON: ";
var_dump(validateJsonAgainstSchema($missingKeyJson, $userSchema)); // bool(false)

// 3. 失敗例: データ型が違うJSON ('id'が文字列になっている)
$wrongTypeJson = '{"id": "3", "name": "Charlie", "isActive": false}';
echo "Wrong Type JSON: ";
var_dump(validateJsonAgainstSchema($wrongTypeJson, $userSchema)); // bool(false)

// 4. 失敗例: 構文的に無効なJSON (末尾にカンマがある)
$invalidSyntaxJson = '{"id": 4, "name": "Dave", "isActive": true,}';
echo "Invalid Syntax JSON: ";
var_dump(validateJsonAgainstSchema($invalidSyntaxJson, $userSchema)); // bool(false)

このPHPコードは、あるJSON形式の文字列が、指定されたルール(スキーマ)通りに作られているかを厳密に検証するためのカスタム関数 validateJsonAgainstSchema を定義しています。この検証は2つのステップで行われます。

まず、第一のステップとして、PHP 8.3から利用可能になった json_validate() 関数を使い、渡された文字列がJSONとして正しい構文で書かれているかを高速にチェックします。この関数は、JSON文字列を引数に取り、構文が正しければtrue、不正であればfalseを返します。構文エラーが見つかった時点で、関数は即座にfalseを返して処理を終了します。

構文チェックを通過すると、第二のステップに進みます。ここでは json_decode() を使ってJSON文字列をPHPの連想配列に変換し、より詳細な内容の検証を行います。あらかじめ定義されたスキーマ配列に基づき、必須のキーが存在するか、そして各キーの値がスキーマで指定されたデータ型(例えば「整数」や「文字列」など)と一致するかを一つずつ確認します。全てのキーとデータ型がスキーマの定義と完全に一致した場合にのみ、この関数は最終的にtrue(検証成功)を返します。一つでもルール違反があればfalse(検証失敗)を返します。

このサンプルコードは、JSONの正しさを2段階で検証します。まずjson_validate()で構文をチェックしますが、この便利な関数はPHP 8.3以降でなければ利用できない点に注意してください。次にjson_decode()でデータをPHPの配列に変換しますが、第二引数にtrueを指定して連想配列にすることが非常に重要です。この指定がないとオブジェクトが返され、後続のキー存在チェックが正しく機能しません。また、この検証関数はネストしたオブジェクトや、あってもなくてもよいオプションのキーには対応していません。スキーマに定義されていない余分なキーが含まれていても検証を通過するため、より厳密な仕様が求められる場合は、コードの追加修正や専用ライブラリの利用を検討する必要があります。

【PHP8.x】json_validate関数の使い方 | いっしー@Webエンジニア