リモートワーク中のある日
ワイ「(カタカタカタカタ・・・ッターン!)」
息子(2歳)「パパ,お仕事捗ってそうだね!」
ワイ「仕事?ちゃうで.これは自分専用のダイエット管理ツールや!」
ワイ「リモートワークやと,仕事せんでもバレへんからなぁ」
ワイ「Slack だけ即レスしとけば,仕事できる男に見えんねん」
ワイ「その他の時間は個人開発や!」
息子「パパ最近リモートワークで外に全く出ないから,お腹周りがぷにぷにだもんね」
息子「ダイエット管理で体重が減っても,仕事もしてないからお給料も減っちゃうよ?」
ワイ「弊社は給与自己決定やから,仕事せんでも給料はもらえるねん」
社長「(お前 Discord ミュートにし忘れてて全部聞こえとるからな...!)」
新しい機能を追加したい
ワイ「よしよし,新しい機能でも追加するか!」
ワイ「1ヶ月前の自分の体重と,今日の体重とで」
ワイ「どれだけ差があるかを計算する機能を作るで」
ワイ「体重が1kg以上減っていたら,アプリ内通貨の”痩せコイン”がもらえる仕組みや...!」
ワイ「今流行の ダイエット2Earn や!」
ワイ「まずは,今日の日付を取得するところからやな」
ワイ「日付操作には,Carbon
というライブラリが便利らしいから,使ってみよか」
ワイ「なになに, Laravel にはもともと Carbon は入っとるから」
ワイ「わざわざインストールしなくてええんか」
ワイ「Laravel はさすが便利やな〜」
ワイ「まずは Carbon を import
して...」
use Carbon\Carbon;
ワイ「今日の日付を取得してみるで」
$today = Carbon::today('Asia/Tokyo');
// 2022-06-01 00:00:00
ワイ「おぉ〜,簡単やな」
ワイ「そして,1ヶ月前の日付も取得せなあかんな」
ワイ「なになに,Carbon は日付の足し引きも簡単にできるんやな」
ワイ「1ヶ月引くには, subMonth()
を使えば良さそうやな」
$oneMonthAgo = $today->subMonth();
// 2022-05-01 00:00:00
ワイ「できたできた」
ワイ「あとは,それぞれの体重をデータベースから取得して」
ワイ「引き算するだけやな!」
// 今日の体重を取得する
$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()
を使えば見れるよ!」
$today = Carbon::today('Asia/Tokyo');
// 2022-06-01 00:00:00
$todayId = spl_object_id($today);
// 3502
ワイ「お,このインスタンスの ID は 3502 ってことやな!」
息子「そうだね」
息子「じゃぁ,この $today
から1ヶ月引いて,またオブジェクト ID を見てみるね」
$oneMonthAgo = $today->subMonth();
// 2022-05-01 00:00:00
$oneMonthAgoId = spl_object_id($oneMonthAgo);
// 3502
ワイ「ほんまや...!」
ワイ「同じインスタンスが返ってきてるやんけ!」
ワイ「知らんかったわ...」
ワイ「でも,それじゃぁどうしたらええんや?」
ワイ「こんな風に...」
$today = Carbon::today();
$oneMonthAgo = Carbon::today()->subMonth();
ワイ「2回 Carbon インスタンスを作ったらええんか?」
息子「それでもいいけど...」
息子「他にもいくつか方法があるよ!」
息子「例えば」
$today = Carbon::today('Asia/Tokyo');
$oneMonthAgo = $today->copy()->subMonth();
息子「こうやってかけば」
息子「copy()
が $today
に入っている Carbon インスタンスの clone
を作ってくれるから」
息子「subMonth()
は $today
とは別のインスタンスに対して実行されるよ」
ワイ「おお!これは便利やな!」
ワイ「直感的やし,分かりやすいな!」
息子「他にも...」
$today = Carbon::today('Asia/Tokyo');
$oneMonthAgo = $today->toImmutable()->subMonth();
息子「こうすれば, copy()
を使ったときと同じで, $today
とは別インスタンスが返ってくる」
息子「しかも,これはイミュータブルにして返してくれるから」
息子「$oneMonthAgo
は不変なインスタンスになるの」
ワイ「イミュータブルにできるん!?」
ワイ「そっちの方が混乱が無くてええやんけ!」
ワイ「でも,それなら $today
からイミュータブルにしたいなぁ」
ワイ「あっ」
$today = Carbon::today('Asia/Tokyo')->toImmutable();
$oneMonthAgo = $today->subMonth();
ワイ「こうしたらええやんけ!」
ワイ「ワイ,天才やなぁ」
息子「パパ,残念!」
息子「全然天才じゃない!」
ワイ「ファッ!?」
ワイ「なんでそんなこと言うねん!」
ワイ「天才的な思いつきやろ!?」
息子「CarbonImmutable
っていう, Carbon のイミュータブルバージョンがあるよ」
ワイ「ファッ!?!?」
ワイ「そんなものが...」
息子「使い方は Carbon と同じで」
$today = CarbonImmutable::today('Asia/Tokyo');
$todayId = spl_object_id($today);
// 3503
$oneMonthAgo = $today->subMonth();
$oneMonthAgoId = spl_object_id($oneMonthAgo);
// 3518
息子「こんな風に書いてあげたら,自動的に新しいインスタンスで返してくれるの」
ワイ「ファーーーー」
ワイ「もうこれでええやん!」
ワイ「なんで最初から教えてくれへんかったんや!」
息子「ごめんごめん,笑」
息子「パパが本当になにも知らなくて,ついつい楽しくなっちゃった」
ワイ「(2歳に遊ばれている...)」
CarbonImmutable で書き直してみる
ワイ「じゃぁさっきのダイエット管理アプリを」
ワイ「CarbonImmutable で書き直してみるか...!」
- use Carbon\Carbon;
+ use Carbon\CarbonImmutable;
// 今日の日付を CarbonImmutable で取得する
- $today = Carbon::today('Asia/Tokyo');
+ $today = CarbonImmutable::today('Asia/Tokyo');
// 1ヶ月前の日付を取得する
$oneMonthAgo = $today->subMonth();
ワイ「よし...!できたで!」
ワイ「ブラウザをリロードしてみると...」
ダイエットツール君「よく頑張ったな!1痩せコイン!」
ワイ「やった〜!」
ワイ「ちゃんと表示されたで!」
その夜
ワイ「ダイエット管理ツールの新機能もできたことだし」
ワイ「今日はご褒美にアイス6個食べるで!」
息子「(だめじゃん...)」
息子「(これじゃいつまで経っても痩せないよ...)」
息子「(こっそり Carbon に戻しとこ)」