PHPのstdClassの動きが環境によって違った件

スズキです。PHPのstdClassのプロパティにアクセスしようとしたときの挙動が、環境によって異なる現象に遭遇したので、共有です。

やりたかったこと

  • json文字列の中から「orderDate」というプロパティから日付データを取り出したい
  • 「orderDate」というプロパティが存在しない場合は、代わりに今日の日付を使いたい
json文字列のイメージはこんな感じ。
{
    "orderId": 1001,
    "orderDate": "2023-11-30",
    "itemName": "UVコーティングシール"
}

修正前コード(問題あり)

PHPのjson_decodeでjson文字列からstdClassを作って、jsonの中身を使うプログラムです。
// $jsonObjectは「stdClass」クラス
$jsonObject = json_decode($jsonString, false);
try {
    $prop = $jsonObject->orderDate;  // ①orderDateがないときはExceptionが発生する…はず?
    $orderDate = new DateTime($prop);  // ②$propがnullだとTypeErrorが発生
} catch (Exception $e) {
    $orderDate = new DateTime();  // ③今日の日付を使う
}
①の行にて「orderDate」というプロパティがないとき、Exceptionが発生してくれれば、catchブロックの③にジャンプして今日の日付を$orderDateにセットできる、ということを目論んだコードなのですけど、これがダメでした。 自分の開発環境では①にてErrorExceptionが発生したので、期待通りcatchブロックへジャンプしたのですが、別のサーバに乗せたら①にてErrorExceptionは発生せず、nullが取得されたのです。nullが取得されたことで、その後の②でTypeErrorが発生したのですが、TypeErrorはExceptionを継承していないのでcatchできず、結局処理としてはエラーになってしまったというわけです。 つまり、json_decodeで取得した「stdClass」の挙動が、環境によって異なったのですね。個人的には、 $jsonObject->orderDate; のところで、プロパティが無ければnullが取れるのが直感的で好きです。

修正後コード(問題解消)

「stdClass」クラスの挙動の違いはさておき、そもそもjsonのプロパティがないときの処理を例外処理を利用して実現しようとしているのが圧倒的によくないので、普通にif文で書き直しました。なんで例外処理でやろうと思ったのだろう、当時の私…
// $jsonObjectは「stdClass」クラス
$jsonObject = json_decode($jsonString, false);
if (property_exists($jsonObject, 'orderDate') && !empty($jsonObject->orderDate)) {
    $prop = $jsonObject->orderDate;
    $orderDate = new DateTime($prop);
} else {
    $orderDate = new DateTime();
}

まとめ

ということで、「stdClass」クラスに存在しないプロパティにアロー演算子(->)でアクセスしたときの挙動は環境によって異なり、ErrorExceptionが発生したり、nullが取得できたりする、というメモでした。PHPのバージョン違いかも?と思いきや、確認したら同じバージョン番号だったので謎は深まるばかり。 どういう環境だと挙動が異なるのか、についての調査は難航しそうだったので、今回はこのへんで…