PHPのarray_uniqueを使って、3つ以上のDateTimeが同じ日時かどうか比較する

単純な話なんだけど忘れそうなのでメモ

# 結論

DateTimeクラス同士を比較する場合は、Unixタイムスタンプに出力してから比較を行う。
PHP7.0.4以前のバージョンの場合、modify()をした後にgetTimestamp()を実行すると意図せずに日付が変わることがあるらしいので注意。

参考:[DateTime::getTimestamp()すると日付が変わる件]()
参考:[PHP :: Bug #71525 :: Calls to date_modify will mutate timelib_rel_time, causing date_date_set issues](https://bugs.php.net/bug.php?id=71525)

```php
// 比較したいDateTimeクラスのオブジェクトを配列に格納する
$dates = [
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01')
];

// 配列の要素全てにgetTimestamp()の返却値を格納する
$dates = array_map(function ($date) {
    return $date->getTimestamp();
}, $dates);

// 3つ以上の値が全て等しいか比較する
if (count(array_unique($dates)) === 1) {
    // 3つ以上の値が全て等しい場合
    echo '3つ以上の値が全て等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値が等しくない';
}

// 結果:3つ以上の値が全て等しい
```

array_uniqueは、第2引数を省略した場合、string型の変換を行なってから重複した値の削除を行う。
DateTimeクラスをそのまま比較しようとすると、array_uniqueの処理中にstring型に変換できないため怒られる。

```php
// 比較したいDateTimeクラスのオブジェクトを配列に格納する
$dates = [
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01')
];

// 3つ以上の値が全て等しいか比較する
if (count(array_unique($dates)) === 1) {
    // 3つ以上の値が全て等しい場合
    echo '3つ以上の値が全て等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値が等しくない';
}
```

出力されるエラー

```
PHP Recoverable fatal error:  Object of class DateTime could not be converted to string in sample.php on line 5
```

また、第2引数を指定することで変換方法を指定することもできる。
詳しくは[公式ドキュメント](https://www.php.net/manual/ja/function.array-unique.php)を参照。
型変換を行わずに重複削除を行うこともできるが、DateTimeクラスのオブジェクト同士の比較はややこしいので混乱の元になりそう…


DateTimeクラスのオブジェクト同士の比較（緩やかな比較の場合）

```php
// 比較したいDateTimeクラスのオブジェクトを定義する
$date1 = new DateTime('2019-01-01');
$date2 = new DateTime('2019-01-01');

// DateTimeクラスのオブジェクト同士の比較
// 緩やかな比較の場合
if ($date1 == $date2) {
    echo '緩やかな比較（==）の結果、オブジェクト同士は等しい';
} else {
    echo '緩やかな比較（==）の結果、オブジェクト同士は等しくない';
}

// 結果:緩やかな比較（==）の結果、オブジェクト同士は等しい
```

DateTimeクラスのオブジェクト同士の比較（厳密な比較の場合）

```php
// 比較したいDateTimeクラスのオブジェクトを定義する
$date1 = new DateTime('2019-01-01');
$date2 = new DateTime('2019-01-01');
// 厳密な比較の場合
if ($date1 === $date2) {
    echo '厳密な比較（===）の結果、オブジェクト同士は等しい';
} else {
    echo '厳密な比較（===）の結果、オブジェクト同士は等しくない';
}

// 結果:厳密な比較（===）の結果、オブジェクト同士は等しくない
```

型変換を行わずにarray_unique()を実行する

```php
// 比較したいDateTimeクラスのオブジェクトを配列に格納する
$dates = [
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01'),
    new DateTime('2019-01-01')
];

// 3つ以上の値が全て等しいか比較する（第2引数にSORT_REGULARを指定する）
if (count(array_unique($dates, SORT_REGULAR)) === 1) {
    // 3つ以上の値が全て等しい場合
    echo '3つ以上の値が全て等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値が等しくない';
}

// 結果:3つ以上の値が全て等しい
```

# 3つ以上の値が等しいかどうか調べる

PHPで3つ以上の値が同じかどうか判定するには、count()とarray_unique()を使った要素数の比較が便利である。

全ての値が等しいか調べるパターン

```php
// 3つ以上の値を配列としてまとめる
$strings = ['A', 'A', 'A'];

// 3つ以上の値が全て等しいか比較する
if (count(array_unique($strings)) === 1) {
    // 3つ以上の値が全て等しい場合
    echo '3つ以上の値が全て等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値が等しくない';
}

// 結果:3つ以上の値が全て等しい
```

```php
// 3つ以上の値を配列としてまとめる
$strings = ['A', 'A', 'B'];

// 3つ以上の値が全て等しいか比較する
if (count(array_unique($strings)) === 1) {
    // 3つ以上の値が全て等しい場合
    echo '3つ以上の値が全て等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値が等しくない';
}

// 結果:3つ以上の値が等しくない
```

いずれか1つ以上の値が等しいか調べるパターン

```php
// 3つ以上の値を配列としてまとめる（等しい値があるもの）
$strings = ['A', 'B', 'B'];

// 3つ以上の値の中で、いずれか1つでも等しい値があるか調べる
if (count(array_unique($strings)) < count($strings)) {
    // 3つ以上の値の中で、いずれか1パターンが等しい
    echo '3つ以上の値の中で、いずれかの値が等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値の中で、等しい値は存在しない';
}

// 結果:3つ以上の値の中で、いずれかの値が等しい
```

```php
// 3つ以上の値を配列としてまとめる（等しい値がないもの）
$strings = ['A', 'B', 'C'];

// 3つ以上の値の中で、いずれか1つでも等しい値があるか調べる
if (count(array_unique($strings)) < count($strings)) {
    // 3つ以上の値の中で、いずれか1パターンが等しい
    echo '3つ以上の値の中で、いずれかの値が等しい';
} else {
    // 3つ以上の値が等しくない場合
    echo '3つ以上の値の中で、等しい値は存在しない';
}

// 結果:3つ以上の値の中で、等しい値は存在しない
```