結論
DateTimeとDateTimeImmutableのちがいは、最初に設定した日時(ベースの日付)を保持するかどうかの違いです。
具体例
イミュータブルなDateTimeImuクラスとミュータブルなDateTimeMuクラスを作成し、それぞれテストを実行してそのふるまいの違いを見てみます。
1.クラス概要
テストされるクラス
- src\Domain\Date\DateTimeImu.php
- src\Domain\Date\DateTimeMu.php
テストクラス
- tests\DateTimeImmutableTest.php
- tests\DateTimeMutableTest.php
2.クラス詳細
テストされるクラス
src\Domain\Date\DateTimeImu.php
<?php
namespace Vendor\App\Domain\Date;
use DateTimeImmutable;
class DateTimeImu
{
private DateTimeImmutable $dateTimeImu;
public function __construct(string $dateString)
{
$this->dateTimeImu = new DateTimeImmutable($dateString);
}
public function getDateTimeImu()
{
return $this->dateTimeImu;
}
}
src\Domain\Date\DateTimeMu.php
<?php
namespace Vendor\App\Domain\Date;
use DateTime;
class DateTimeMu
{
private DateTime $dateTime;
public function __construct(string $dateString)
{
$this->dateTime = new DateTime($dateString);
}
public function getDateTime()
{
return $this->dateTime;
}
}
DateTimeImmutableのテストクラス
tests\DateTimeImmutableTest.php
<?php
namespace Vendor\App;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Vendor\App\Domain\Date\DateTimeImu;
class DateTimeImmutableTest extends TestCase
{
/**
* @test
*/
public function getDateTimeImu_指定した日付オブジェクトを取得できること()
{
$dateTimeImu = new DateTimeImu('2021/09/01');
$expected = new DateTimeImmutable('2021/09/01');
$this->assertEquals($expected, $dateTimeImu->getDateTimeImu());
}
/**
* @test
*/
public function getDateTimeImu_イミュータブルな日付オブジェクトの文字列を取得できること()
{
$dateTimeImu = new DateTimeImu('2021/09/01');
$dateTimeImu->getDateTimeImu()->modify('+7 day');
$dateTimeImuString = $dateTimeImu->getDateTimeImu()->modify('+7 day')->format('Y/m/d');
$expected = '2021/09/08';
$this->assertEquals($expected, $dateTimeImuString);
}
}
DateTimeMutableのテストクラス
tests\DateTimeMutableTest.php
<?php
namespace Vendor\App;
use DateTime;
use PHPUnit\Framework\TestCase;
use Vendor\App\Domain\Date\DateTimeMu;
class DateTimeMutableTest extends TestCase
{
/**
* @test
*/
public function getDateTime_指定した日付オブジェクトを取得できること()
{
$dateTimeMu = new DateTimeMu('2021/09/01');
$expected = new DateTime('2021/09/01');
$this->assertEquals($expected, $dateTimeMu->getDateTime());
}
/**
* @test
*/
public function getDateTime_ミュータブルな日付オブジェクトの文字列を取得できること()
{
$dateTimeMu = new DateTimeMu('2021/09/01');
$dateTimeMu->getDateTime()->modify('+7 day');
$dateTimeMuString = $dateTimeMu->getDateTime()->modify('+7 day')->format('Y/m/d');
$expected = '2021/09/15';
$this->assertEquals($expected, $dateTimeMuString);
}
}
3.検証結果
テストはいずれも期待値を満たしており、通るようになっていますが、それぞれ結果が異なっています。
DateTimeImmutable
イミュータブルな日付クラスであるDateTimeImmutableは、日付の変更を繰り返しても基準日が変わらない。そのため、modifyメソッドで何度日付を編集しても基準日は最初にインスタンスを生成するときに渡した日付('2021/09/01')が保持される。
※以下tests\DateTimeImmutableTest.phpより一部抜粋
/**
* @test
*/
public function getDateTimeImu_イミュータブルな日付オブジェクトの文字列を取得できること()
{
$dateTimeImu = new DateTimeImu('2021/09/01');
$dateTimeImu->getDateTimeImu()->modify('+7 day');
$dateTimeImuString = $dateTimeImu->getDateTimeImu()->modify('+7 day')->format('Y/m/d');
$expected = '2021/09/08';
$this->assertEquals($expected, $dateTimeImuString);
}
図解
2021/09/01を渡してDateTimeImmutableオブジェクトをnew・・・①
↓
①の日付オブジェクトに7日プラス・・・②
↓
②のオブジェクトに7日プラス・・・③
↓
基準日が2021/09/01のままなので、結果は2021/09/01に7日間を足した2021/09/08になる
DateTimeMutable
ミュータブルな日付クラスであるDateTimeMutableは、日付の変更を繰り返すと、その都度基準日が変わるため、modifyメソッドで日付を編集すると、最初にインスタンスを生成するときに渡した日付('2021/09/01')が保持されない。
※以下tests\DateTimeMutableTest.phpより一部抜粋
/**
* @test
*/
public function getDateTime_ミュータブルな日付オブジェクトの文字列を取得できること()
{
$dateTimeMu = new DateTimeMu('2021/09/01');
$dateTimeMu->getDateTime()->modify('+7 day');
$dateTimeMuString = $dateTimeMu->getDateTime()->modify('+7 day')->format('Y/m/d');
$expected = '2021/09/15';
$this->assertEquals($expected, $dateTimeMuString);
}
図解
2021/09/01を渡してDateTimeMutableオブジェクトをnew・・・①
↓
①の日付オブジェクトに7日プラス・・・②
↓
②のオブジェクトに7日プラス・・・③
↓
基準日が②の段階で2021/09/08になり、③では②の日付に7日足しているので、結果は2021/09/01に14日間を足した2021/09/15になる
まとめ
本記事では、PHPのDateTimeクラスとDateTimeImmutableクラスの違いについて紹介しています。大きな差異は最初に設定した日時(ベースの日付)を保持するかどうかの違いですが、具体的なテストケースと図解を用いてできる限りわかりやすく説明しています。