この記事ではCarbonを使って日付操作を行う際に起こりやすい問題についての記事です。
CarbonはPHPに用意された日付と時刻操作のためのライブラリです。
Laravelなどのフレームワークでも手軽に使うことができる便利なものです。
しかし起こりやすいミスで期待した日付を取得できない場合があります。
そのミスの原因と対処法を詳しく紹介していきます。
この記事を読むメリット
- Carbonを使う際のはまりやすいミスを理解できる
- Carbonのはまりポイントを防いだ使い方が分かる
それでは早速紹介していきます。
Carbonで日付が更新/上書きされてしまう
まずCarbonでよく起こってしまうミスについて実例を使って紹介します。
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function index()
{
$today = Carbon::today();
$threeDaysAgo = $today->addDays(3);
if ($today->eq($threeDaysAgo)) {
dd('同じ日付です。');
} else {
dd('同じ日付ではありません。');
}
}
}
上のコードでは、「今日」の日付「$today」を取得し、そこに「addDays(3)」を使って3日後の日付「$threeDaysAfter」を作成しています。
2つの日付は異なるように思えますが、「$today->eq($threeDaysAgo)」を使って2つの日付を比較すると、結果は「同じ日付です。」になります。
Carbonの日付比較は以下記事で詳しく紹介しています。
Carbonを使って日付の比較を行う方法【Laravel】【PHP】
$todayが上書きされている
理由は$todayが「addDays(3)」で3日後の値に上書きされているからです。
「$today->addDays(3)」とした時点で$todayの日付も3日後に更新されます。
結果比較した時に同じ日付として処理が行われてしまいました。
エンジニアにおすすめ書籍
エンジニアになりたて、これから勉強を深めていきたいという方におすすめの書籍はこちら!
Carbonで上書き/更新を防ぐ方法
先ほどのようなミスに陥らないようにする方法は大きく3つあります。
- Carbon\CarbonImmutableを利用する
- copy()を使う
- 再利用しない
1つずつ説明します。
Carbon\CarbonImmutableを利用する
まず1つ目は「Carbon\CarbonImmutableを利用する」です。
CarbonImmutableとは、Carbonのimmutable(不変)版です。
Carbonとは異なり、インスタンスが作られた時点のものから変わらないのが特徴です。
先ほどのコードを書き換えてみます。
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function index()
{
$today = Carbon::today();
$todayCarbonImmuutable = CarbonImmutable::today();
$threeDaysAgo = $todayCarbonImmuutable->addDays(3);
if ($todayCarbonImmuutable->eq($threeDaysAgo)) {
dd('同じ日付です。');
} else {
dd('同じ日付ではありません。');
}
}
}
「use Carbon\CarbonImmutable;」としてCarbonImmutableが使えるようにします。
「CarbonImmutable::today()」を使って今日の日付を取得します。
すると期待通り「同じ日付ではありません」と表示されました!
copy()を使う
2つ目はcopy()を使う方法です。
こちらはCarbonで作成したインスタンスを基にコピーを行いながら処理をしていく方法です。
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function index()
{
$todayCarbonImmuutable = CarbonImmutable::today();
$threeDaysAgo = $todayCarbonImmuutable->addDays(3);
// copy()を使う
$today = Carbon::today();
$threeDaysAgoByTodayCopy = $today->copy()->addDays(3);
if ($today->eq($threeDaysAgoByTodayCopy)) {
dd('copy: 同じ日付です。');
} else {
dd('copy: 同じ日付ではありません。');
}
}
}
「$today->copy()」とすることで、インスタンスをコピーした状態でaddDays(3)の処理を行っています。
$todayには変化はありません。
こちらも期待通り「同じ日付ではありません。」が表示されました。
再利用しない
最後は再利用しないことです。
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function index()
{
$threeDaysAgo = Carbon::today()->addDays(3);
if (Carbon::today()->eq($threeDaysAgoByTodayCopy)) {
dd('copy: 同じ日付です。');
} else {
dd('copy: 同じ日付ではありません。');
}
}
}
Carbonは「mutable(可変)」であるということの認識が大事です。
今回のような単純なものだと$todayと変数にする必要もないのかなと思いました。
処理の内容に応じてシンプルに書ける方法を選択するのがベストかと思います。
Carbonの沼にハマらないよう注意しよう
いかがだったでしょうか。
CarbonImmutableやcopy()を使うとCarbonの上書きや更新がされることを避けることができます。
知らないと意図しない動きに何時間も費やしてしまうこともあるかと思います。
ハマった時にしっかりと周辺知識を固めると良いなと最近感じています。
何か指摘点などあればXなどで頂ければ幸いです。
参考: