Carbon 型に実装されているメソッドは破壊的メソッド
PHP で時刻を扱うには Carbon というライブラリが使用できます。
ですが、Carbon\Carbon 型のオブジェクトは可変 (mutable) であり、実装されているメソッドは破壊的 (destructive) メソッドのため、オブジェクトそのものの値が変更 (modify) されてしまいます。
when you use a modifier on a Carbon instance, it modifies and returns the same instance
https://carbon.nesbot.com/docs/
<?php
require_once "vendor/autoload.php";
use Carbon\Carbon;
$now = Carbon::now();
print("now = " . $now . "\n");
$myDatetime = $now->startOfHour();
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
// 何なら代入する必要もない
$myDatetime->addMinutes(30);
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
$ php -f carbon_example.php
now = 2023-04-22 21:28:23
now = 2023-04-22 21:00:00
myDatetime = 2023-04-22 21:00:00
now = 2023-04-22 21:30:00
myDatetime = 2023-04-22 21:30:00
ですので、値を再利用したい場合は copy() などを挟む必要があります。
<?php
require_once "vendor/autoload.php";
use Carbon\Carbon;
$now = Carbon::now();
print("now = " . $now . "\n");
+// copy() を挟むことで元のオブジェクトに影響を与えない
-$myDatetime = $now->startOfHour();
+$myDatetime = $now->copy()->startOfHour();
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
-$myDatetime->addMinutes(30);
+$myDatetime->copy()->addMinutes(30);
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
$ php -f carbon_example2.php
now = 2023-04-22 21:36:35
now = 2023-04-22 21:36:35
myDatetime = 2023-04-22 21:00:00
now = 2023-04-22 21:36:35
myDatetime = 2023-04-22 21:00:00
CarbonImmutable を使おう
しかし、それではくどいため CarbonImmutable を使うのが良いかもしれません。この型を使うと、addMinutes などのメソッドを呼び出しても元のインスタンスは変更されず、新しいインスタンスを戻り値として返します。
when you use it on CarbonImmutable, it returns a new instances with the new value.
<?php
require_once "vendor/autoload.php";
-use Carbon\Carbon;
+use Carbon\CarbonImmutable;
-$now = Carbon::now();
+$now = CarbonImmutable::now();
print("now = " . $now . "\n");
$myDatetime = $now->startOfHour();
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
$myDatetime->addMinutes(30);
print("now = " . $now . "\n");
print("myDatetime = " . $myDateTime . "\n");
$ php -f carbon_example3.php
now = 2023-04-22 21:40:03
now = 2023-04-22 21:40:03
myDatetime = 2023-04-22 21:00:00
now = 2023-04-22 21:40:03
myDatetime = 2023-04-22 21:00:00
おわりに
他にもハマりそうな人が居るかもしれない思ったので記事にしました。公式ドキュメントのかなり最初の方に書かれているので、もしかしたら自分以外の人はそんなミスは犯さないのかもしれませんが……orz