本文へスキップ
BecomeCoder

PHPコース · 第7章 Webアプリの実務 · レッスン24

データベース ― PDOでSELECT・INSERT・UPDATE

ローカル実施

導入

実際の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/catchPDOException を受け止めます。

<?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件 INSERTSELECT で取り出して表示、という一連の流れを実際に書いて動かしてみましょう。プレースホルダを使わずに文字列連結でSQLを組み立てるとどうなるか、次のレッスンで学ぶ前に一度想像してみるのもおすすめです。