Laravelの日時ライブラリ
Laravelを使い始めて日時ライブラリがたくさんあり、迷ったので備忘録として。
注意
Laravel8系での話になります。Laravel5系とかだとIlluminate\Support\Carbon
はまたちょっと違うので参考程度にしてください。
Carbon\Carbon
おなじみの日時ライブラリ。組み込みのDateTimeクラスを継承している。
mutableなので、インスタンスを直接変更するため注意が必要。
$time = Carbon::create(2021, 12, 25); // 2021-12-25 00:00:00
$time->addDay(); // 2021-12-26 00:00:00
$time->addDay(); // 2021-12-27 00:00:00 (直感的には2021-12-26であってほしい)
Carbon::now()->copy()->addDay()
のようにインスタンスをコピーしてから使わないとコードのあちこちで変更があった時に追うのが辛くなる。
テストで時間を固定させたい時は Carbon::setTestNow()
PHPに触り始めた人だとサラッと流しがちなのでバグの温床になりやすい。(1時間ハマった)
Illuminate\Support\Carbon
Carbon\Carbon
とCarbon\CarbonImmutable
を拡張した日時ライブラリ。実装を見ると分かる通り、Laravel8だともうsetTestNow()
しか実装がない。 (テストで日時を固定できるメソッド)
Carbon\CarbonImmutable
Carbonの immutable版。組み込みのDateTimeImmutable
クラスを継承している。
こちらは新しいインスタンスが返されるため、copy()
する必要がない。
インスタンスが作られた一番最初の状態を持つので、コードを順に追う必要がなくなる。
$time = CarbonImmutable::create(2021, 12, 25); // 2021-12-25 00:00:00
$time->addDay(); // 2021-12-26 00:00:00
$time->addDay(); // 2021-12-26 00:00:00 (宣言時のものを基準にする)
テストで時間を固定したい時は CarbonImmutable::setTestNow()
注意
CarbonImmutable::setTestNow()
だと上手く時間が設定出来ない可能性があるので、テスト時のみCarbon::setTestNow()
推奨
- CarbonImmutable::setTestNow()だとCarbonImmutable::now()などの時間固定ができる。
- Carbon::setTestNow()だとCarbon::now()などの時間固定が出来る。
DateTime
Carbonの元になっているPHP組み込みの日時ライブラリ。
何か特別な理由がない限りはLaravelではCarbonを使った方が楽に感じる。
DateTimeImmutable
CarbonImmutableの元になっているPHP組み込みの日時ライブラリ。
何か特別な理由がない限りはLaravelではCarbonImmutableを使った方が楽に感じる。
まとめ(CarbonImmutableを使おう)
出来ることならばCarbonImmutableを採用したい。(プロジェクトで統一することが一番大切)
また、DateTimeを使うことで柔軟なインターフェース設計にできることを@mpywさんに教えていただきました。
ありがとうございます
その他追記があれば随時更新していきます。
https://t.co/iNHK3FiuHW
— 素人 (@mpyw) December 21, 2021
interface と class で必ずしも一致させる必要がない点も注意してください!自分はモジュラモノリスプロジェクトで以下のようにしました
interface
引数: DateTimeInterface, 返り値: DateTimeImmutable
class
引数: DateTimeInterface, 返り値: CarbonImmutable
一点追記です
— 素人 (@mpyw) December 21, 2021
class のコンストラクタ引数に関しては、interface での束縛対象にならないと思うので、CarbonImmutable 直接指定もありだとは思います
この場合、インスタンス生成は「使ってもらう側」が全て巻き取り、「使う側」には全く意識させない設計が必要となりますが