みなさん映画スーパーマリオ見ましたか?
私はIMAX吹替で見てきたのですが……いやー…………めっちゃ面白かったですね!!
特にラストシーンでクッパが親指を立てながら溶岩湖に沈んでいくシーンは涙無しには見られませんでした。
さて全く関係ないのですがDateTimeの話です。
DateTimeImmutable::__constructに不正な値を突っ込んだらどうなるでしょう。
エラーがあった場合は Exception を発生させます。
わおアバウト。
ということでPHP8.3からは、もっと細かくいいかんじに例外を扱えるようになります。
以下は該当のRFC、More Appropriate Date/Time Exceptionsの紹介です。
PHP RFC: More Appropriate Date/Time Exceptions
Introduction
このRFCでは、Date/Timeエクステンションに固有の例外とエラーを導入します。
現在、Date/Timeが発生させるのはただのException
とError
です。
これは全く具体的ではないため、Date/Timeの例外を適切に捕捉することができません。
なお本RFCの範囲外ですが、ついでに警告・エラーのメッセージを改善します。
Proposal
本RFCは、警告やエラーを整理し、Date/Timeエクステンション固有の例外やエラーを導入します。
概要は以下のとおりです。
readonlyプロパティの変更など汎用的な例外についてはErrorをスローします。
これはユーザランドコードのミスに対してPHP本体が行う処理です。
ユーザランドコードや自由入力テキストからの不正な入力についてはValueErrorを発生します。
不正なTimezoneなど、無効なデータはDateErrorを発生します。
初期化されていないオブジェクトにはDateObjectErrorを発生します。
ユーザ入力などテキストからのパースに失敗すると、DateExceptionを継承した例外を発生します。
・タイムゾーン生成のエラーはDateInvalidTimeZoneExceptionを発生します。
・DateTime::sub()
に相対時刻を渡すなど、実行できない操作などはDateInvalidOperationExceptionを発生します。
・パースに失敗してDateTime
オブジェクトが生成できないときはDateMalformedStringExceptionを発生します。
・パースに失敗してDatePeriod
オブジェクトが生成できないときはDateMalformedPeriodStringExceptionを発生します。
なお、Date/Timeを手続き型として使う場合は影響を受けず、現在と同じ警告・エラーが発生します。
Backward Incompatible Changes
互換性のない変更点。
エポックがPHPのintに収まらない場合、ValueErrorではなくDateRangeErrorを発生させるようになりました。
DateRangeErrorはValueErrorのサブクラスではありません。
これは32ビットプラットフォームでのみ問題になります。
これまでDateTime::sub()
で発生していた、Only non-special relative time specifications are supported for subtraction
の警告はDateInvalidOperationExceptionの例外になります。
これを警告で放置するのは、有用なふるまいではありません。
これまでDateInterval
で発生していたUnknown or bad format (%s) at position %d (%c): %s
およびString '%s' contains non-relative elements
の警告はDateMalformedIntervalStringExceptionの例外になります。
Proposed PHP Version(s)
PHP8.3
RFC Impact
エクステンションやopcodeに対する影響はありません。
Unaffected PHP Functionality
手続き型での使用については、これまでと動作は変わりません。
オブジェクト型で使用する場合のみ影響を受けます。
Voting
投票者の2/3の賛成で受理されます。
投票期間は2022/12/15から2022/12/31です。
本RFCは、賛成25反対1の賛成多数で可決されました。
Implementation
感想
手続き型とオブジェクト型で処理分ける必要ある?
$i = DateInterval::createFromDateString('last Monday of');
$sub = (new DateTimeImmutable())->sub($i);
// PHP8.2 Warning: DateTimeImmutable::sub(): Only non-special relative time specifications are supported for subtraction
// PHP8.3 Fatal error: DateMalformedIntervalStringException
$sub = date_sub(new DateTime(), $i);
// PHP8.2 Warning: date_sub(): Only non-special relative time specifications are supported for subtraction
// PHP8.3 Warning: date_sub(): Only non-special relative time specifications are supported for subtraction
全部Exceptionにしてしまっていいと思うのだが。
どういう経緯があったのかは調べていないのでわかりませんが、まあ今どきdate_xxx
を使ってるコードなんて古すぎてどうしようもないだろうからそのままにしといてやろう的な判断でもあったのかもしれませんね。
ということでDateTimeを使っている場合、今後はよりいいかんじに例外を扱えるようになります。
あとどうでもいいけど調査中、date_subの第一引数がDateTimeInterfaceではなくDateTimeだということに気が付いた。
$sub = date_sub(new DateTimeImmutable(), new DateInterval('P1D'));
// Fatal error: Uncaught TypeError: date_sub(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given
どうして?