2歳息子「パパ，PHP の Carbon はミュータブルだよ？」

## リモートワーク中のある日
ワイ「（カタカタカタカタ・・・ッターン！）」

息子（2歳）「パパ，お仕事捗ってそうだね！」

ワイ「仕事？ちゃうで．これは自分専用の**ダイエット管理ツール**や！」
ワイ「リモートワークやと，仕事せんでもバレへんからなぁ」
ワイ「Slack だけ**即レス**しとけば，仕事できる男に見えんねん」
ワイ「その他の時間は個人開発や！」

息子「パパ最近**リモートワークで外に全く出ない**から，お腹周りがぷにぷにだもんね」
息子「ダイエット管理で体重が減っても，仕事もしてないからお給料も減っちゃうよ？」

ワイ「弊社は**給与自己決定**やから，仕事せんでも給料はもらえるねん」

社長「（お前 Discord **ミュートにし忘れてて**全部聞こえとるからな．．．！）」

## 新しい機能を追加したい
ワイ「よしよし，新しい機能でも追加するか！」
ワイ「1ヶ月前の自分の体重と，今日の体重とで」
ワイ「どれだけ差があるかを計算する機能を作るで」
ワイ「体重が1kg以上減っていたら，アプリ内通貨の”痩せコイン”がもらえる仕組みや．．．！」
ワイ「今流行の **ダイエット2Earn** や！」

ワイ「まずは，今日の日付を取得するところからやな」
ワイ「日付操作には，`Carbon` というライブラリが便利らしいから，使ってみよか」
ワイ「なになに， Laravel にはもともと Carbon は入っとるから」
ワイ「わざわざインストールしなくてええんか」
ワイ「Laravel はさすが便利やな〜」

ワイ「まずは Carbon を `import` して．．．」
```php
use Carbon\Carbon;
```

ワイ「今日の日付を取得してみるで」
```php
$today = Carbon::today('Asia/Tokyo');
// 2022-06-01 00:00:00
```

ワイ「おぉ〜，簡単やな」
ワイ「そして，1ヶ月前の日付も取得せなあかんな」
ワイ「なになに，Carbon は日付の足し引きも簡単にできるんやな」
ワイ「1ヶ月引くには， `subMonth()` を使えば良さそうやな」
```php
$oneMonthAgo = $today->subMonth();
// 2022-05-01 00:00:00
```

ワイ「できたできた」
ワイ「あとは，それぞれの体重をデータベースから取得して」
ワイ「引き算するだけやな！」
```php
// 今日の体重を取得する
$todayWeight = BodyWeight::query()
    ->where('measurement_date', $today)
    ->first();

// 1ヶ月前の体重を取得する
$oneMonthAgoWeight = BodyWeight::query()
    ->where('measurement_date', $oneMonthAgo)
    ->first();

// 1ヶ月前の体重から今日の体重を引く
$diffWeight = $oneMonthAgoWeight->value - $todayWeight->value;

return $diffWeight >= 1
  ? 'よく頑張ったな！1痩せコイン！' // 1kg以上体重が減っていた場合
  : 'もっと努力しろ！デブが！' // 1kgも体重が減っていない場合
```

## 新機能完成！のはずが．．．
ワイ「よし！できたで！！」
ワイ「サイトにアクセスしてみてみよか」

> ダイエットツール君「もっと努力しろ！デブが！」

ワイ「そんな言い方しなくても．．．」
ワイ「ワイだって努力してんねん．．．」
ワイ「1日に食べるアイスの量，5個から4個に減らしたねん！！」

息子「（自分が設定した文言でしょ．．．）」
息子「（っていうかアイス食べすぎでしょ．．．）」
息子「（僕には全然くれないくせに．．．）」

ワイ「あれ？」
ワイ「記録をみると，今日の体重は57kgで」
ワイ「先月は58kgやから」
ワイ「褒めてもらえるはずなんやけど．．．？」

## 息子先生登場
息子「パパ，ちょっとコード見せて！」

ワイ「おお，息子くん」
ワイ「PHP のコード読めるん？」
ワイ「そういえばこの間，牛さんの絵本とか言って，」
ワイ「オライリー社の**C実践プログラミング**[^1]をパパの本棚から引っ張り出しとったからな」

息子「あ〜，パパ， PHP の Carbon は**ミュータブル**だよ？」

ワイ「**ミュウダブる**！？」
ワイ「幻のポケモンは世界に1体しかおらんのやで！」
ワイ「そんなんできるの，もう **セレクトバグ**[^2] やないか．．．」

息子「パパ，**令和ベイビー**に向かっていつの時代の話をしてるの？」
息子「”ミュウダブる” じゃなくて ”ミュータブル”！」
息子「可変ってこと！」

ワイ「可変．．．？変数なんていつでも上書きできてまうやん」
ワイ「てか自分で自分のこと令和ベイビーって言うなや」

息子「そういう話じゃなくてね」
息子「ミュータブルは，**オブジェクトが作成されたあとも状態を変えることができる**って意味なの」
息子「その反対が**イミュータブル**で，一度作られたら**状態は変えられない**の」
息子「そしてね」
息子「Carbon の日付操作系のメソッドは，自分自身，つまり `$this` を返すの」

ワイ「`$this` を返す．．．？」

息子「そう． だから， パパが使った `subMonth()` は，自分自身の日付を1ヶ月分引くから」
息子「実は `$today` も `$oneMonthAgo` も**同じインスタンス**なの」
息子「実験してみる？」

息子「まずは，さっきみたいに現在の日付を取得して」
息子「返ってきた Carbon インスタンスのオブジェクト ID を見てみよう」

ワイ「オブジェクトの ID とか見れるん？」

息子「PHP ビルトインの `spl_object_id()` を使えば見れるよ！」
```php
$today = Carbon::today('Asia/Tokyo');
// 2022-06-01 00:00:00

$todayId = spl_object_id($today);
// 3502
```

ワイ「お，このインスタンスの ID は 3502 ってことやな！」

息子「そうだね」
息子「じゃぁ，この `$today` から1ヶ月引いて，またオブジェクト ID を見てみるね」
```php
$oneMonthAgo = $today->subMonth();
// 2022-05-01 00:00:00

$oneMonthAgoId = spl_object_id($oneMonthAgo);
// 3502
```

ワイ「ほんまや．．．！」
ワイ「同じインスタンスが返ってきてるやんけ！」
ワイ「知らんかったわ．．．」
ワイ「でも，それじゃぁどうしたらええんや？」
ワイ「こんな風に．．．」
```php
$today = Carbon::today();
$oneMonthAgo = Carbon::today()->subMonth();
```
ワイ「2回 Carbon インスタンスを作ったらええんか？」

息子「それでもいいけど．．．」
息子「他にもいくつか方法があるよ！」
息子「例えば」
```php
$today = Carbon::today('Asia/Tokyo');
$oneMonthAgo = $today->copy()->subMonth();
```
息子「こうやってかけば」
息子「`copy()` が `$today` に入っている Carbon インスタンスの `clone` を作ってくれるから」
息子「`subMonth()` は `$today` とは**別のインスタンスに対して実行される**よ」

ワイ「おお！これは便利やな！」
ワイ「直感的やし，分かりやすいな！」

息子「他にも．．．」
```php
$today = Carbon::today('Asia/Tokyo');
$oneMonthAgo = $today->toImmutable()->subMonth();
```
息子「こうすれば， `copy()` を使ったときと同じで， `$today` とは別インスタンスが返ってくる」
息子「しかも，これは**イミュータブルにして返してくれる**から」
息子「`$oneMonthAgo` は不変なインスタンスになるの」

ワイ「イミュータブルにできるん！？」
ワイ「そっちの方が混乱が無くてええやんけ！」
ワイ「でも，それなら `$today` からイミュータブルにしたいなぁ」
ワイ「あっ」
```php
$today = Carbon::today('Asia/Tokyo')->toImmutable();
$oneMonthAgo = $today->subMonth();
```
ワイ「こうしたらええやんけ！」
ワイ「ワイ，天才やなぁ」

息子「パパ，残念！」
息子「全然天才じゃない！」

ワイ「ファッ！？」
ワイ「なんでそんなこと言うねん！」
ワイ「天才的な思いつきやろ！？」

息子「`CarbonImmutable` っていう， **Carbon のイミュータブルバージョン**があるよ」

ワイ「ファッ！？！？」
ワイ「そんなものが．．．」

息子「使い方は Carbon と同じで」
```php
$today = CarbonImmutable::today('Asia/Tokyo');
$todayId = spl_object_id($today);
// 3503

$oneMonthAgo = $today->subMonth();
$oneMonthAgoId = spl_object_id($oneMonthAgo);
// 3518
```
息子「こんな風に書いてあげたら，自動的に**新しいインスタンスで返してくれる**の」

ワイ「ファーーーー」
ワイ「もうこれでええやん！」
ワイ「なんで最初から教えてくれへんかったんや！」

息子「ごめんごめん，笑」
息子「パパが本当になにも知らなくて，ついつい楽しくなっちゃった」

ワイ「（2歳に遊ばれている．．．）」

## CarbonImmutable で書き直してみる
ワイ「じゃぁさっきのダイエット管理アプリを」
ワイ「CarbonImmutable で書き直してみるか．．．！」

```diff_php
- use Carbon\Carbon;
+ use Carbon\CarbonImmutable;

// 今日の日付を CarbonImmutable で取得する
- $today = Carbon::today('Asia/Tokyo');
+ $today = CarbonImmutable::today('Asia/Tokyo');

// 1ヶ月前の日付を取得する
$oneMonthAgo = $today->subMonth();
```
ワイ「よし．．．！できたで！」
ワイ「ブラウザをリロードしてみると．．．」

> ダイエットツール君「よく頑張ったな！1痩せコイン！」

ワイ「やった〜！」
ワイ「ちゃんと表示されたで！」

## その夜
ワイ「ダイエット管理ツールの新機能もできたことだし」
ワイ「今日はご褒美にアイス6個食べるで！」

息子「（だめじゃん．．．）」
息子「（これじゃいつまで経っても痩せないよ．．．）」
息子「（こっそり Carbon に戻しとこ）」

[^1]: オライリー社が出版している C 言語の書籍．表紙に牛の絵が書いてある．
![51HY6s6u2LL._SL500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333871/38f4ff41-e036-80aa-d342-03372b7a4037.jpeg)

[^2]: ゲームボーイ版ポケモン（赤など）で，セレクトを沢山押してポケモンのレベルを 100 にしたり，マスターボールを 99 個にしたりするバグ技のこと．