PHPの日時をコントロールするDateTimeクラスはよく見ます。同じようなクラスにDateTimeImmutableもあります。
使い方が同じなのでどうでもいいと思われがちですが、ちがいをきちんと理解して使い分けましょうという話です。
というか絶対に使い分けてほしい!
DateTimeとDateTimeImmutableのちがい
DateTimeとDateTimeImmutableのちがいは、
最初に設定した日時を残すか?
これだけです。
DateTime | Mutable (変更する) 元データ消える |
DateTimeImmutable | Immutable (変更しない) 元データ残す |
クラス名そのままですね?DateImmutableはDateTimeの元データを変更できない用に用意されたクラスです。
メソッドもほぼ同じでそのパラメータも同じです。使い方は同じと考えていいです。
ふたつのクラスの違いはcreateFrom***()です。
DateTime | createFromImmutable() DateTimeImmutableからDateTimeを作る。 ※ PHP7.3以上 |
DateTimeImmutable | createFromMutable() DateTimeからDateTimeImmutableを作る。 ※ PHP5.6以上 |
ちがいが分かるサンプルコード
ふたつのオブジェクトをメソッドで変更するサンプルコードを作りました。一気に実行します。
DateTimeは、コンストラクタで指定した日時(元データ)がメソッドで変更するたびに更新されます。
しかしDateTimeImmutableは、コンストラクタで指定した日時はメソッドを実行しても変わりません。
かといって、DaeTimeImmutableで変更できないことはありません。できます。
DateTime系クラスは、メソッドのリターンで自身と同じクラスのオブジェクトを返します。DateTimeImmutableは元のオブジェクトはそのままに、変更したオブジェクトを新しく作って返します。
DateImmutableの日時を変更したければ、メソッドの結果のオブジェクトを使えばいいです。
一方、DateTimeは元のオブジェクトを変更してそれをメソッドの結果で返します。
(元のオブジェクトと戻り値のオブジェクトは同じなので、メソッドの戻り値を使う意味がない。)
基本DateTimeImmutableを使う
DateTimeはデータを更新しつづけることができます。でもバグになりやすいです。
サンプルコードで見てみましょう。
関数やクラスの中でDateTimeオブジェクトを変更すると、その内容が元のオブジェクトに反映されます。
オブジェクト指向はとくに、クラスの集合体でできてるので、どこで、どのように変更されているか分かりづらいです。
また、データベースから取得したデータを知らぬところで変更されては困るでしょう。
データを変更するときは、はっきりと分かるようにする。
これは基本です。これに最適なのがDateTimeImmutable。メソッドで変更しても元データは残りますから。
さっきのサンプルをDateTimeImmutableに変えて実行します。
プログラマはクラス・関数名で処理を想像する
DateTimeImmutableを使うようにすすめる最大の理由は、プログラマの性質です。
プログラマの仕事は大量のコードを読みます。作業をするとき一言一句読むなんてことはしません。
クラス名・メソッド名・関数名で何をしているのか当たりをつけて関係なさそうならスルーします。
そのとき、DateTimeオブジェクトを見たら

と直感で思います。
(逆にDateTimeImmutableを見ると『変わらないデータだな』と思う。)
それなのに変更がなかったとしたら... 時間のムダです。
日時オブジェクトはDateTimeImmutableを使う。
変更するときだけDateTimeにして変更する。
DateTimeImmutableオブジェクトを上書き。
としてくれたほうが余計な時間を使いません。
他人が読みやすいプログラムを書くのもプログラマの仕事です。
(プログラマの作業時間も利益に直結している。)
一人で最後まで責任をもてる仕事ならいいですが、そんな仕事ないですからね? ほぼ。
コードはこんな感じになります。
これで、『どこで』『どのように』日時が更新されたか分かると思います。
データの更新は、はっきり分かるようにしないとバグの温床になる。