IT関連
PR

【PHP】json_encodeでJSONの空オブジェクト{}を表現させる

saratogax
記事内に商品プロモーションを含む場合があります

GooglePlay の「REST Resource: purchases.subscriptionsv2」 API のレスポンス仕様で以下のオブジェクトがあった。
(一部抜粋)

{
  "autoRenewingPlan": {
    "autoRenewEnabled": boolean,
    "priceChangeDetails": {
      object
    },
    "installmentDetails": {
      object
    }
  } 
}

この構造、autoRenewEnabled が true の時は上記のような構成になっているのですが、false に該当する時は以下の構造になります。

{
  "autoRenewingPlan": {}
}

これを php で表現しようとすると空配列を定義することになりますよね。

$json = [
  "autoRenewingPlan" => [],
];

しかし、これだと json_encode の結果が空配列になってしまいます。

{"autoRenewingPlan":[]}

今回は、この問題を解決して空のオブジェクトを返せるようにしてみましょう。

JSON_FORCE_OBJECTで配列のオブジェクトを返す

json_encode には 2 番目の引数でオプションを指定することができます。

その中に、「JSON_FORCE_OBJECT」というオプションがあります。

非連想配列を使用した場合に、配列ではなくオブジェクトを出力します。 出力を受け取る側がオブジェクトを期待しており、配列が空っぽである場合などに特に便利です。

https://www.php.net/manual/ja/json.constants.php#constant.json-force-object

これを使えば解決しそうですね。

$json = [
  "autoRenewingPlan" => [],
];

echo json_encode($json, JSON_FORCE_OBJECT) . PHP_EOL;

って思ったのですが、以下の記事で問題点が指摘されていました。

どうやら他の配列項目もオブジェクトに変換してしまうようです。

確かに、以下のような配列を json_encode すると問題点がわかりますね。

連想配列ならいいのですが、単なる配列だとインデックスの部分も考慮されちゃうのか。

$json = [
  "autoRenewingPlan" => [],
  "test" => [1, 2, 3],
];

echo json_encode($json, JSON_FORCE_OBJECT) . PHP_EOL;

{"autoRenewingPlan":{},"test":{"0":1,"1":2,"2":3}}

stdClassで代用する

ちょうど上記の記事に書かれていたのですが、空オブジェクトは stdClass で対応が可能なようです。

$json = [
  "autoRenewingPlan" => new stdClass(),
];

echo json_encode($json) . PHP_EOL;

これの結果は以下のようになります。

{"autoRenewingPlan":{}}

JSON_FORCE_OBJECT のオプションも不要なので、意図していない変換がされてしまう心配もないですね。

ちなみに、new stdClass()(object) [] と書いても同じ結果になります。

$json = [
  "autoRenewingPlan" => (object) [],
];

echo json_encode($json) . PHP_EOL;

どちらでも構いませんが、配列リテラルの中に直接書くなら (object) [] のほうが短くて読みやすいですね。

受け取り側でも同じ問題が起きる

実は、この問題はレスポンスを受け取って詰め直すときにも再発します。

json_decode() の第 2 引数に true を渡すと、JSON のオブジェクトは連想配列として返されます。

このとき、{}(空オブジェクト)は空配列になります。

その配列をそのまま json_encode() に通すと、空配列は [] になるので、元は {} だったものが [] に化けて戻ってきます。

GooglePlay の API レスポンスをいったん json_decode($body, true) で受けて、加工してから別のシステムへ渡す、という作りだとここで壊れます。

オブジェクトの形を保ったまま扱いたいなら、第 2 引数を付けずに json_decode($body) で受けるのが確実です。

この場合、空オブジェクトは stdClass のインスタンスとして返ってくるので、再エンコードしても {} のままです。

参考(出典)

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました