7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【PHP8.3】DateTimeのエラーハンドリングがいいかんじになるよ

Posted at

みなさん映画スーパーマリオ見ましたか?
私はIMAX吹替で見てきたのですが……いやー…………めっちゃ面白かったですね!!
特にラストシーンでクッパが親指を立てながら溶岩湖に沈んでいくシーンは涙無しには見られませんでした。

さて全く関係ないのですがDateTimeの話です。
DateTimeImmutable::__construct不正な値を突っ込んだらどうなるでしょう。

01.png

エラーがあった場合は Exception を発生させます。

わおアバウト。

ということでPHP8.3からは、もっと細かくいいかんじに例外を扱えるようになります。
以下は該当のRFC、More Appropriate Date/Time Exceptionsの紹介です。

PHP RFC: More Appropriate Date/Time Exceptions

Introduction

このRFCでは、Date/Timeエクステンションに固有の例外とエラーを導入します。

現在、Date/Timeが発生させるのはただのExceptionErrorです。
これは全く具体的ではないため、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

どうして?

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?