JSONはほとんどの言語で容易に利用可能な、最も普及したデータフォーマットです。
仕様が非常に簡単で人間にも読みやすいというところが、XMLなどの『厳密だがややこしい』フォーマットにとってかわった理由といえるでしょう。
RESTがSOAPやJava RMIなんかを駆逐したのと同じような話ですね。
しかし仕様が簡単すぎるがゆえの問題も多々あります。
なんといっても最大の欠点が、コメントを書けないということです。
2026年11月時点で最新のJSON定義であるRFC8259にもコメントに関する仕様はありません。
{
"foo":"bar",
"_comment":"ここコメント"
}
_で始まるキーは無視するなど、運用側でがんばってどうにかしているのが現状です。
ということでこれをどうにかしようとJSONCやJSON5のような仕様が生まれましたが、まああんまり使われていませんよね。
{
// 1行コメント
"foo":"bar",
"_comment": /* 複数行コメントも書ける */ "ここコメント"
}
// 末尾カンマはデフォルト禁止
{
// 1行コメント
"foo":"bar",
"_comment": /* 複数行コメントも書ける */ "ここコメント",
}
// 末尾カンマも可
どうして普及しないのかというと、そもそも標準仕様ではないので導入が面倒なのと、あとは相互運用性に問題が出るからです。
設定ファイル等で自分自身が使うだけなら問題ありませんが、それをそのまま相手に渡しても相手側が動きません。
なら結局そのままJSONでいいやとなりがちなわけです。
さてPHPでは、なんと言語仕様でJSONコメント書けるようにしようぜという話が進んでいます。
わりと評価も高いので、おそらくはこのまま通ってPHP8.7で利用可能になるんじゃないかと思います。
以下は該当のRFC、Opt-in JSON Comments and Trailing Commasの紹介です。
Opt-in JSON Comments and Trailing Commas
Introduction
JSONにコメントを書けるようになります。
末尾カンマも書けます。
デフォルトは厳密なJSONのままです。
このRFCでは、2定数JSON_ALLOW_COMMENTSとJSON_ALLOW_TRAILING_COMMASを追加します。
多くのツールは、設定ファイルとしてJSONを利用します。
設定ファイルでは、ユーザは設定の意図をコメントで説明したい場合があります。
また項目の追加を容易にするため末尾カンマを使いたいこともあります。
現在json_decode()はいずれも許可していないため、ユーザランドライブラリは手動でこれらを削除しなければなりません。
$config = <<<'JSON'
{
// ローカル開発用
"host": "localhost",
"port": 5432, /* PostgreSQLのデフォルト */
"options": [
"persistent",
"utf8",
],
}
JSON;
$data = json_decode($config, true, flags: JSON_ALLOW_COMMENTS | JSON_ALLOW_TRAILING_COMMAS);
// ['host' => 'localhost', 'port' => 5432, 'options' => ['persistent', 'utf8']]
$data = json_decode($config, true);
// NULL, json_last_error_msg(): "Syntax error"
2つのフラグは独立しており、いずれか片方もしくは両方を有効にすることが可能です。
フラグを指定しない場合は、既存動作のままです。
Proposal
New constants
2つの定数が追加されます。
/**
* 行コメント、ブロックコメントを許可
* @var int
*/
const JSON_ALLOW_COMMENTS = 8388608; // 1 << 23
/**
* 末尾カンマを許可
* @var int
*/
const JSON_ALLOW_TRAILING_COMMAS = 16777216; // 1 << 24
Changed functions
json_decode()の引数$flagsは2定数を受け入れます。
json_validate()の引数$flagsは2定数を受け入れます。
json_encode()は何も変わりません。
コメントや末尾カンマを出力することはありません。
JSON_ALLOW_COMMENTS
このフラグは、2種類のコメントを受け入れます。
・行コメント // 。
・ブロックコメント /* */。改行を含めることができます。
JSONで任意の空白を入れられるところに、コメントを書くことができます。
Perl型の行コメント#は受け付けません。
JSON_ALLOW_TRAILING_COMMAS
このフラグは、空でない配列やオブジェクトの末尾にカンマをひとつだけ受け入れます。
[1, 2, 3,]は[1, 2, 3]と同じ。
{"a": 1, "b": 2,}は{"a": 1, "b": 2}と同じ。
[,]はシンタックスエラー。最初には置けない。
[1,,]はシンタックスエラー。許容するのはひとつだけ。
1,はシンタックスエラー。トップレベルには置けない。
[1,}はシンタックスエラー。そもそもJSONとして正しくない。
Behavior that does not change
フラグを使わない場合は、これまでと挙動に違いはありません。
120025件のテストを行った結果、差は出ませんでした。
JSON_OBJECT_AS_ARRAYなどの既存定数はこれまでどおり使用可能で、組み合わせることもできます。
コメントと末尾カンマはネストの深さに影響を与えず、引数$depthの動作は変わりません。
新しいエラーコードはありません。
Examples
JSON_ALLOW_COMMENTSだけの場合、末尾カンマはエラーになります。
var_dump(json_decode($config, true, flags: JSON_ALLOW_COMMENTS)); // NULL
echo json_last_error_msg(); // Syntax error
テキスト内にある/*等の文字列は、ただのテキストです。
var_dump(json_decode('{"url": "https://example.com/*"}', true, flags: JSON_ALLOW_COMMENTS));
// array(1) { ["url"]=> string(21) "https://example.com/*" }
json_validateも、json_decodeと同じフラグを受け入れます。
var_dump(json_validate('{"a": 1, /* note */}', flags: JSON_ALLOW_COMMENTS | JSON_ALLOW_TRAILING_COMMAS));
// bool(true)
JSON_THROW_ON_ERRORも、これまでと同じ動作です。
try {
json_decode('[1,,]', flags: JSON_ALLOW_TRAILING_COMMAS | JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo $e->getMessage(); // Syntax error
}
Relation to JSON5, JSONC and JWCC
事前検討のスレッドにおいて、これはJSON5が導入されるということかと尋ねられましたが、そうではありません。
JSON5はJSONの大幅な拡張であり、この2つ以外にも様々な機能が追加されます。
また一部の機能は既存の仕様に変更が入ります。
本RFCで導入されるフラグは、JSONCやJWCCに近いものです。
| 構文 | JSON | JSON_ALLOW_COMMENTS | 両フラグ | JSONC | JWCC | JSON5 |
|---|---|---|---|---|---|---|
| //・/**/ | × | 〇 | 〇 | 〇 | 〇 | 〇 |
| 末尾カンマ | × | × | 〇 | △ | 〇 | 〇 |
| CRのみ改行 | - | 〇 | 〇 | 〇 | × | 〇 |
| U+2028改行 | - | × | × | × | × | 〇 |
| NaN・Infinity他 | × | × | × | × | × | 〇 |
まとめると、JSON_ALLOW_COMMENTSでJSONC構文を受け入れ、JSON_ALLOW_COMMENTS | JSON_ALLOW_TRAILING_COMMASでJWCCを受け入れます。
ただひとつだけ小さな違いがあり、JWCCの行コメント終了はLFだけですが、PHPではCRも行コメント終了になります。
これらのフラグは、PHPのJSONをJSONC仕様にするものではありません。
JSON_ALLOW_JSONCというフラグを導入しなかった理由は、Rejected Featuresの項目を参照ください。
Prior art
既存のJSONパーサも、同じように機能ごとのフラグを提供しています。
| パーサ | コメント | 末尾カンマ |
|---|---|---|
| Chromium base::JSONReader(C++) | JSON_ALLOW_COMMENTS | JSON_ALLOW_TRAILING_COMMAS |
| RapidJSON(C++) | kParseCommentsFlag | kParseTrailingCommasFlag |
| Jackson(Java) | JsonReadFeature.ALLOW_JAVA_COMMENTS | JsonReadFeature.ALLOW_TRAILING_COMMA |
| .NET System.Text.Json | JsonCommentHandling.Skip | AllowTrailingCommas |
| seld/jsonlint(PHP) | JsonParser::ALLOW_COMMENTS | - |
本RFCは、Chromiumと同じ定数名を使っています。
Demand
需要。
多くの既存PHPプロジェクトは、コメント付きJSONを受け入れています。
・colinodell/json5 JSON5パーサ。
・adhocore/json-comment JSONコメント削除ライブラリ。
・seld/jsonlint JSON検証ライブラリ。
VSCodeのsettings.json、TypeScriptのtsconfig.json、Dev Containerのdevcontainer.jsonなどもコメントを許可します。
これらのファイルを読み込むツールは、コメントを読めるパーサが必要です。
Why not in userland
ユーザランドライブラリは、json_decode()する前にコメントを削除するというアプローチをとっています。
・エラーが起きた場合、元のJSONとエラー行が一致しなくなることがあります。
・2回パースすることになります。
・json_validate()は対応していません。
ネイティブ実装なら、パースは一回で済むし、エラーの場所も一致します。
Backward Incompatible Changes
後方互換性のない変更。
2つのグローバル定数が追加されます。
既に同じ定数を使っていた場合はエラーになります。
ただし検索したところ、この名前を使っているコードは見当たりませんでした。
json_decodeの引数$flagは未知のビットを無視するため、誤ってフラグを与えていた場合、現在はエラーが起きているコメント付きJSONが正常にパースされるようになります。
Proposed PHP Version(s)
次のマイナーバージョン。
PHP8.7の予定。
RFC Impact
To the Ecosystem
エコシステムへの影響。
IDE・静的アナライザなどは2つの定数を追加する必要があります。
To Existing Extensions
既存の拡張機能への影響。
変更点はext/jsonだけです。
内部パーサphp_json_parser_init()は新しいオプションを受け入れるようになります。
Performance
2万個のオブジェクトを含む7.6MBのJSONドキュメントを使用してCPUを測定した結果です。
| 検証 | 現行 | 本RFC | 影響 |
|---|---|---|---|
| json_decode、フラグ無し | 354,777,244 | 360,436,080 | +1.60% |
| json_validate、フラグ無し | 333,889,491 | 339,548,009 | +1.69% |
| json_decode、フラグ有り | - | 360,436,080 | フラグがない場合と同じ |
| json_decode全行にコメント入れた | - | 405,796,303 | - |
厳密なJSONのパースにかかるコストは、json_decodeが+0.56%、json_validateが+0.59%となります。
Open Issues
未解決の問題はありません。
Future Scope
今後のRFCでは、必要に応じてフラグを追加できるでしょう。
たとえば単一引用符の対応、引用符なしのキー、16進数などです。
Patches and Tests
Rejected Features
却下された機能。
One JSON_ALLOW_JSONC flag
まとめてJSON_ALLOW_JSONCの1定数にする。
事前のスレッドで、コメントと末尾カンマをまとめて1定数にすることを提案されました。
これはJSONCの標準規格に従うためと、組み合わせ爆発を防ぐためです。
このRFCでは、以下の理由からそれを採用しませんでした。
・JSONCには安定した標準規格が存在しません。
仕様は未だドラフトであり、変更される可能性があります。
JSONCという名前を採用すると、仕様が変更された場合に追随しなければなりません。
・JSONCでは、末尾カンマはサポートしてもしなくてもいいオプションとなっています。
従って、定数JSON_ALLOW_JSONCでは末尾カンマを定義できません。
・既存の他のパーサも個別のフラグを採用しています。
後日、安定した標準規格が登場した場合には、既存のフラグを組み合わせた新しい定数が採用される可能性はあります。
本RFCはその提案を妨げるものではありません。
Full JSON5 support
JSON5フルサポート。
JSON5は、コメントと末尾カンマ以外にも多くの機能が追加されています。
中にはNaNやInfinityのように既存のデータ構造に影響を与えるものもあります。
従って、それらを導入する場合は個別に議論する必要があります。
Hash comments
#のコメント。
JavaScript・JSONC・JWCC・JSON5には#コメントがありません。
本RFCも#に対応しません。
Nested block comments
コメントのネスト。
JavaScript・JSONCはブロックコメントのネストを許可しません。
本RFCも/* /* */ */には対応しません。
More than one trailing comma
複数の末尾カンマ。
JavaScriptでは、[1,,2]は空を含む有効な配列です。
JSONC・JWCC・JSON5は末尾カンマを1つだけ受け入れます。
本RFCは[1,,]も[1,,2]も受け入れません。
感想
これは便利!!
手動で新規作成しようと思うと意外と面倒ですが、既存の設定ファイルを編集するという観点ではJSONは非常に優れたフォーマットです。
INIはネストできないから項目が増えてくるとつらい、XMLはめんどくさすぎる、YAMLは個人的に好きじゃない、TOMLは見たことがない、とやっぱりJSONが最も優れたフォーマットです。
そう、コメントと末尾カンマ以外は。
そんなわけで、今後は設定ファイルのJSONに気軽にコメントや末尾カンマを書けるようになりますね。
めでたしめでたし。
なおjson_encodeには対応しない、すなわちコメント付きJSONを出力することができない、ということからわかるように、決してコメント付きJSONを作成する機能ではありません。
他のシステムにデータを渡すときなどは、これまでどおり厳密なJSONを使ってねということになります。
まだPHP8.6も出ていないというのに、早々とPHP8.7に待ち遠しい機能が現れてしまいましたね。
