Builder(ビルダ)クラス の概要と役割を初学者向けにまとめました。
1. Builderとは何か
Builderとは「SQL(データベースへの命令文)を、PHPのコードで安全かつ簡単に組み立てるためのオブジェクト」です。
ポイントはSQLの実行タイミングです。
// ❌ 誤解:ここでデータベースからデータを取得している
$query = Project::where('work_place_id', 1);
実際には、この段階ではデータベースへの通信は1ミリ秒も発生していません。
Builderは「注文書(設計図)に『WHERE work_place_id = 1』という条件を書き足しただけ」の、準備状態のオブジェクトです。
構築フェーズと実行フェーズ
注文(SQL)が確定してデータベースに送信されるのは、最後に get() や paginate() などの データ取得メソッド を呼び出した瞬間だけです。
Project::query() ──> [Builder生成] (空の注文書)
│
▼
->where(...) ──> [条件追加] (「場所の条件」を書き足す)
│
▼
->orderBy(...) ──> [並び替え追加] (「並び順の条件」を書き足す)
│
▼
->paginate(10) ──> 🔥【SQL実行】 (注文書が完成し、データベースへ送信)
データを取りに行く直前まで、「SQLを組み立て中の状態(注文書を書き換えている状態)でキープできる」 のがBuilderの最大の特徴です。
2. なぜBuilderが必要なのか(3つのメリット)
メリット①:条件に応じてSQLを後から「育てられる」
もしBuilderという仕組みがなければ、画面の入力内容(リクエスト)に応じて、生のSQL文字列を if 文でペタペタと結合しながら作らなければなりません。これは空白の入れ忘れなどによる構文エラーや、バグの温床になります。
Builderであれば、オブジェクトに対して後からメソッドを追加するだけで、安全にSQLを組み立てていくことができます。
// 1. 組み立ての開始
$query = Project::query();
// 2. 条件があれば、クエリを「育てる」
if (!empty($filters['skills'])) {
$query->whereIn('skill_id', $filters['skills']);
}
// 3. 最終的な形にして実行
$projects = $query->get();
「途中の状態を維持して持ち運べる」という性質があるからこそ、この $query を別の共通処理クラスやメソッドに引数として渡し、「別ファイルでクエリをさらに育ててもらう」 といった綺麗な設計(責務の分離)が可能になります。
メリット②:SQLインジェクションを自動で防ぐ
ユーザーが検索窓に悪意のあるプログラムを入力したとしても、Builderの where() などのメソッドを通すことで、Laravelの内部で自動的にバインド処理(無害化)が行われます。開発者が意識せずとも、安全なSQLが生成されます。
メリット③:メソッドチェーンによる可読性向上
$query->where(...)->orderBy(...)->get() のように、矢印(->)で処理を繋げて書くことができます。
これは、各メソッドが処理を終えた後に「条件を追加して新しく育った、自分自身のBuilderオブジェクト」を返却(return $this;)しているために実現しています。
3. デバッグ手法:toSql()
Builderが「本当にSQLを実行せずに、裏で設計図を作っているだけなのか」を確かめる最も有効な方法が、toSql() メソッドです。
$query = Project::query()->where('work_place_id', 1);
// 実行をストップし、組み立てられたSQLの文字列を確認する
dd($query->toSql());
上記を実行すると、データベースにはアクセスされず、画面に以下の文字列が出力されます。
"select * from `projects` where `work_place_id` = ?"
※ ? の部分には、安全に処理された値(今回は 1)が後から入ります。
これを見ることで、get() を呼ぶまでは、単なる「SQLの文字列を組み立てている最中の箱」であることが一発で体感できます。