はじめに
ただいま絶賛個人開発でゲームアプリ作成中なのですが、思いがけず初歩的なところでハマったので、備忘録的な感じで残しておきたいと思います。
何にハマったのか
私がハマったのは、簡単に言うと「DB:transaction()(クロージャ)変数のスコープ」です。
……めちゃくちゃ初歩的じゃんって思った方、その通りでございます、、
とはいえ、自分の足りないところを理解して備忘録に残してる自分は褒めてあげたいです(良く言えば再発防止ですね…)
さぁ、それでは具体的にどんなところでハマったのか、お話ししていきます。
私の作っているアプリでは1回の勝負(マッチ)の中で複数のラウンドが紐付くようになっています。
1ラウンドの処理では、ラウンドテーブルへの登録とマッチテーブルへの更新を1つのトランザクションでまとめて実行しており、最初は下記のように書いていました。
$round = new MatchRound();
DB::transaction(function () use ($match, ...) {
$round = MatchRound::create([...]); // クロージャ内のローカル変数
$match->update([...]);
});
return new CpuRoundResult($match->refresh(), $round); // $roundが空
しかし、上記ではラウンドテーブルの登録結果を返却値に入れることはできません。
その理由がまさにクロージャ内変数のスコープ問題です。
クロージャ(無名関数)も独立した普通の関数と同様にスコープを捉える必要がありましたが、IF文とかと同じノリで外側で初期化した変数をクロージャ内で使おうとしてました。
修正後がこちら
$round = DB::transaction(function () use ($match, ...) {
$round = MatchRound::create([...]);
$match->update([...]);
return $round;
});
ラウンドテーブルの更新結果を戻り値とし、それを変数に代入することで解決しました。
他の候補としては、初期化した$roundを参照渡しでクロージャに渡すことも考えましたが、そうすると
-デバッグで追いにくくなる
-クロージャの中と外の結合が強くなる
といったデメリットがあるので、避けました。
さいごに
個人開発はこういった気づきがあるので、とても面白いですね。(書きながら思いましたが、useで渡す変数がいくつかあるので、このトランザクションの処理自体をprivateメソッドに切ってしまってもいいかもしれない…)
内容の難易度を問わず、これからも自分の理解をより深めるために、書き残していきたいと思います。