こんにちは、かつコーチです。
前回の記事で、PHPだけを使って登録・一覧・更新・削除のCRUD処理を一通り実装しました。
たった1つのusersテーブルを操作するだけなのに、db.php・insert.php・list.php・update.php・delete.phpと、5つのファイルを書くことになりました。
「これを、実際のアプリにある会員テーブル・投稿テーブル・コメントテーブル…と全部のテーブル分やるのか」と思うと、少し気が重くなった人もいるのではないでしょうか。
今回は一度立ち止まって、「素のPHPでDB操作をするのがなぜこんなに大変なのか」を整理してみます。
素のPHPでのDB操作、何が大変なのか
①同じようなコードを何度も書くことになる
前回作った4つのファイルを振り返ると、実は多くの部分がほとんど同じ構造をしています。
<?php
// insert.php・update.php・delete.phpに共通する骨組み
$pdo = getPdo();
$sql = '...';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':xxx', $value, PDO::PARAM_XXX);
$stmt->execute();
?>
テーブルがusersだけならまだしも、postsテーブル、commentsテーブルと増えるたびに、この「接続 → SQL準備 → bindValue → execute」という流れを、ほぼ同じ形でひたすら書き続けることになります。
私が個人開発の小さな管理画面を作ったとき、テーブルが5つほどある時点ですでに、似たようなSQL実行コードを20回近く書いていて、「同じことを繰り返しているな」という違和感がずっと拭えませんでした。
②テーブル構造が変わるたびに、複数箇所を書き換える必要がある
usersテーブルに新しくphone(電話番号)という列を追加したとします。
そうすると、insert.phpのSQLとbindValue、update.phpのSQLとbindValue、list.phpの表示部分と、最低でも3つのファイルを見つけて修正しなければなりません。
修正漏れが1箇所でもあると、「一覧には表示されているのに更新画面では反映されない」といった、地味だが原因が分かりにくいバグにつながります。
③SQL文字列の中でミスをしても、実行するまで気づけない
SQLは文字列としてPHPのコード内に書くため、WHEREのスペルミスや、カラム名の書き間違いがあっても、PHP自体の文法チェックでは検出されません。
前回の記事で紹介した「WHERE句を書き忘れて全ユーザーの名前が上書きされた」という私の失敗も、根本的にはこの「実行するまでミスに気づけない」という素のSQLの弱点が原因でした。
④取得したデータが、ただの「連想配列」のままになる
fetch()やfetchAll()で取得したデータは、あくまで$user['name']のようなキー付きの配列です。
配列なので、$user['nema']とタイプミスをしても、PHPはエラーを出さずにnullを返すだけで、画面に何も表示されない状態のまま進んでしまいます。
クラスのプロパティのように$user->nameと書けていれば、少なくともエディタの補完機能でタイプミスに気づきやすくなるのですが、連想配列にはその恩恵がありません。
⑤複数のテーブルを組み合わせる処理が、一気に複雑になる
usersテーブルとpostsテーブルのように、テーブル同士が関連している場合、JOINを使ったSQLを書く必要が出てきます。
SELECT users.name, posts.title
FROM posts
JOIN users ON posts.user_id = users.id
WHERE users.id = :user_id
投稿一覧に「投稿者の名前」も一緒に表示したいだけなのに、SQLは一気に複雑になり、結果を扱うPHP側のコードも、どの列がどちらのテーブルのものか意識しながら書く必要が出てきます。
これがコメント機能やタグ機能まで加わってくると、SQLの複雑さは掛け算的に増えていきます。
「大変さ」の正体を整理する
比較表で振り返る
ここまで挙げてきた大変さを、表で整理してみましょう。
| 課題 | 具体的に困ること |
|---|---|
| コードの重複 | テーブルごとに似たようなCRUDコードを何度も書く |
| 変更への弱さ | カラムを1つ追加するだけで複数ファイルの修正が必要 |
| ミスへの気づきにくさ | SQL文字列のタイプミスが実行するまで分からない |
| データの扱いにくさ | 連想配列のキーのタイプミスに気づけない |
| リレーションの複雑さ | テーブル同士の関連が絡むとSQLが急激に複雑化する |
こうして並べてみると、個々のSQLやPDOの書き方自体は前回までの記事で十分理解できても、「アプリ全体を通して同じことを繰り返し正確に書き続ける」という部分に、大変さの正体があることが分かります。
これはPHPやPDOが悪いわけではなく、「素のSQLをそのまま手で書き続ける」という進め方自体に限界がある、ということです。
この大変さをLaravelはどう解決するのか
Eloquentという仕組みが担う役割
ここから先、本シリーズはLaravelというフレームワークに入っていきますが、その中にEloquentというデータベース操作の仕組みがあります。
Eloquentを使うと、たとえば全件取得は次のようなイメージで書けるようになります(今の時点ではコードの形だけ眺めてもらえれば十分です)。
<?php
// Eloquentを使った場合のイメージ(Laravelパートで詳しく解説します)
$users = User::all();
foreach ($users as $user) {
echo $user->name; // 連想配列ではなく、プロパティとして扱える
}
?>
SQL文を直接書かなくてもUser::all()のような形でデータを取得でき、取得したデータも$user->nameのようにオブジェクトのプロパティとして扱えます。
テーブル同士の関連(JOINが必要な場面)も、あらかじめ関係を定義しておけば、複雑なSQLを書かずに済むようになります。
素のPDOを学んだことが無駄にならない理由
「だったら最初からEloquentだけ学べばよかったのでは」と思うかもしれませんが、そうではありません。
EloquentもPDOも、最終的には同じくSQLを実行してデータベースとやり取りをしています。
Eloquentが裏側で「今どんなSQLを実行しているか」を理解できるかどうかで、パフォーマンスの問題やバグの原因を調査する力が大きく変わってきます。
私自身、Eloquentの挙動が想定と違って悩んだとき、最終的に助けてくれたのは「裏で実行されているSQLはどんな形になっているはずか」というPDO時代の感覚でした。
今回までで味わった「大変さ」を知っているからこそ、この後Eloquentに触れたときに、そのありがたみを実感できるはずです。
まとめ
この記事のポイント
- 素のPHP・PDOでのDB操作は、テーブルが増えるほど似たコードの重複が増えていく
- テーブル構造の変更が複数ファイルへの修正につながり、修正漏れのリスクがある
- SQL文字列のミスや連想配列のキーのタイプミスは、実行するまで気づきにくい
- テーブル同士の関連(JOIN)が絡むと、SQLとコードの複雑さが一気に増す
- この大変さを解決するのがLaravelのEloquentであり、PDOの理解はEloquentを使いこなす土台になる
次に読むべき記事
DB操作の大変さを体感したところで、次はPHPのエラーそのものについて、もう一段深く見ていきましょう。
→ 次の記事:PHPのNotice・Warning・Fatal Errorの違いと読み方