🫠
【Laravel】無名関数についてまとめてみた
はじめに
Laravelで関数を書いているときに、親スコープの変数を使うとエラーが出るタイミングがあったので調べてみました。
事象
$maxAge =20;
$query->join('members', function ($join) {
$join->on('families.id', '=', 'members.family_id')
->where('members.age', '<', $maxAge); // ここで親スコープの変数($maxAge)が使えない
})
// PHP Notice: Undefined variable: ・・・
原因
上記で言うサブクエリ部分は無名関数にあたるので、直接親スコープの変数を使うことができない
解決方法
引き継ぐ変数は、use
で渡す必要がある。
これはLaravelの仕様ではなく、PHP自体の仕様。
$maxAge =20;
$query->join('members', function ($join) use ($maxAge ) {
$join->on('families.id', '=', 'members.family_id')
->where('members.age', '<', $maxAge); // 使える!
})
use
は定義された時点の変数を参照することに注意する。
$maxAge =20;
$query->join('users', function ($join) use ($maxAge ) {
$maxAge = 50;
$join->on('families.id', '=', 'users.family_id')
->where('users.age', '<', $maxAge); // $maxAge = 20;
})
上記を回避するには参照渡しにする必要がある。
ただし、次回 $maxAge
に別の値が代入されると挙動が変わってしまうので、unset()で変数の割当を解除しておくと事故が少ない。
// unsetを使用しない場合
$maxAge =20;
$query->join('members', function ($join) use (&$maxAge ) {
$maxAge = 50;
$join->on('families.id', '=', 'members.family_id')
->where('members.age', '<', $maxAge); // $maxAge = 50;
})
// $maxAge = 50
// unsetを使用した場合
$maxAge =20;
$query->join('members', function ($join) use (&$maxAge ) {
$maxAge = 50;
$join->on('families.id', '=', 'members.family_id')
->where('members.age', '<', $maxAge); // $maxAge = 50;
unset($maxAge);
})
// $maxAge = 20;
ちなみに、1行の無名関数であればアロー関数を使って書くことも可能。(PHP 7.4で追加)
アロー関数なら親スコープの変数も自動で認識してくれるので、場合によってはこちらの方がスッキリ書けることもある。
$maxAge =20;
$query->join('members', fn ($join) => $join->on('families.id', '=', 'members.family_id')
->where('members.age', '<', $maxAge));
クエリビルダの場合はアロー関数のほうが見やすいかもしれない。
おまけ
Laravelで無名関数が使われる例
1. ルートの定義
Route::get('/', function () {
return view('welcome');
});
2. マイグレーションでテーブルを作成する
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
3. サブクエリ
$query ->join('children', function ($join) use ($maxAge) {
$join->on('users.id', '=', 'children.user_id')
->where('children.age', '<' , $maxAge)
})
まとめ
普段何も考えずに使っているとそのエラーが出たときに対処法がわからなくなるので、きちんと理解することが大切だと思いました。
参照渡しは事故が起きそうなのでなるべく使いたくないです。
とりあえず無名関数でuse
を使っているクエリビルダをアロー関数に書き換えようと思いました。
参考記事
Discussion