導入
実際のWebアプリは、商品一覧や会員情報などのデータをデータベース(多くは MySQL)に保存します。レッスン20で少し触れた PDO を、ここでは実際のCRUD(作成・読み取り・更新・削除)操作にそって、もう一歩深く見ていきます(ブラウザの中では実際のデータベースに接続できないため、この章は読み物として進みます)。
説明
まずは接続です。DSN(接続文字列)・ユーザー名・パスワードを渡し、オプションで「エラーが起きたら例外を投げる」モードにしておくのが定番です(例外については次章で詳しく学びます。ここでは「うまくいかなかったときに catch が受け止めてくれる」とだけ覚えておけば十分です)。
<?php
$pdo = new PDO(
"mysql:host=localhost;dbname=shop;charset=utf8mb4",
"user",
"pass",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
SELECT(読み取り) は prepare() でSQLの雛形を用意し、? の場所に値を渡して execute() します。値を文字列連結で組み込まず、必ず ?(プレースホルダ)を使うのが鉄則です(理由は次のレッスン26で詳しく扱います)。
<?php
$stmt = $pdo->prepare("SELECT * FROM products WHERE price <= ?");
$stmt->execute([1000]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); // 連想配列の配列で受け取る
foreach ($rows as $row) {
echo $row["name"], ": ", $row["price"], "円\n";
}
INSERT(作成) も同じ形で、名前付きプレースホルダ(:name のような書き方)も使えます。
<?php
$stmt = $pdo->prepare("INSERT INTO products (name, price) VALUES (:name, :price)");
$stmt->execute(["name" => "消しゴム", "price" => 80]);
echo "新しいIDは " . $pdo->lastInsertId() . "\n";
UPDATE(更新)・DELETE(削除) も文の形が違うだけで、書き方は同じです。
<?php
$stmt = $pdo->prepare("UPDATE products SET price = ? WHERE id = ?");
$stmt->execute([90, 5]);
echo $stmt->rowCount() . "件更新しました\n"; // 影響を受けた行数
エラー時は try/catch で PDOException を受け止めます。
<?php
try {
$pdo->exec("INSERT INTO products (name, price) VALUES ('壊れたデータ', 'abc')");
} catch (PDOException $e) {
echo "データベースエラー: " . $e->getMessage() . "\n";
}
fetchAll() は全件、fetch() は1件だけ取り出すメソッドです。件数が多いテーブルを全部 fetchAll() すると重くなるので、必要な件数だけ LIMIT で絞る・1件ずつ処理するなど、SQL側の工夫も実務では大切です。
演習
(読み物のため自動判定はありません)手元に MySQL や SQLite を用意できる人は、php -S localhost:8000 で動くPHPファイルを作り、PDO でテーブルを作成(CREATE TABLE)→データを1件 INSERT→SELECT で取り出して表示、という一連の流れを実際に書いて動かしてみましょう。プレースホルダを使わずに文字列連結でSQLを組み立てるとどうなるか、次のレッスンで学ぶ前に一度想像してみるのもおすすめです。