PHPでSQL実行!PDOのprepare, execute, fetchの基本操作

PHPからデータベースへの接続が完了したら、次はいよいよSQL文を実行してデータを操作します。PHPでデータベースを扱う際には、セキュリティを確保し、効率的に処理を行うための決まった「作法」があります。

それが、**「1. 準備 (Prepare) → 2. 実行 (Execute) → 3. 結果取得 (Fetch)」**という3ステップの流れです。

この記事では、PDOを使ってこの一連の操作を行う方法と、結果を配列として受け取る方法について詳しく解説します。


目次

1. Step 1: SQL文を「準備」する (prepare)

データベースを操作する上で最も注意すべきことの一つがSQLインジェクションという攻撃です。これを防ぐための現代的な手法が「プリペアドステートメント (Prepared Statement)」であり、PDOではprepare()メソッドがその役割を担います。

これは、SQL文のテンプレート(雛形)を先にデータベースに送って「こういう命令を実行するよ」と準備させるイメージです。このとき、ユーザーからの入力値など、変動するデータ部分は?(プレースホルダ)としておきます。

<?php
// ($pdo はデータベース接続済みのPDOオブジェクトとする)

// 評価が ? 以上のレビューを取得するSQL文のテンプレートを準備
$sql = "SELECT * FROM reviews WHERE rating >= ?";
$stmt = $pdo->prepare($sql);
?>

prepare()メソッドは、準備されたSQL文を格納したPDOStatementオブジェクト(ここでは変数$stmt)を返します。


2. Step 2: SQLを「実行」する (execute)

SQL文の準備ができたら、execute()メソッドを使って実際に実行します。このとき、prepare()で用意したプレースホルダ (?) に、実際の値を配列の形で渡します。

<?php
// プレースホルダに渡したい値
$rating_threshold = 4;

// 配列で値を渡してSQLを実行
$stmt->execute([$rating_threshold]);
?>

PDOは内部で、渡された値を安全な形に処理してからSQL文にはめ込んでくれるため、開発者はSQLインジェクションのリスクを心配することなく、安全にクエリを実行できます。


3. Step 3: 結果を「取得」する (fetch, fetchAll)

SELECT文を実行した場合、その結果をデータベースからPHPの変数に取り出す必要があります。この処理を「フェッチ (Fetch)」と呼びます。

fetchAll(): 全件をまとめて取得

fetchAll()は、SQLの実行結果をすべて取得し、多次元配列として返します。結果の件数が少ない場合に便利です。

// 結果をすべて連想配列として取得
$reviews = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 取得したデータをループで表示
foreach ($reviews as $review) {
    echo htmlspecialchars($review['book_title'], ENT_QUOTES, 'UTF-8') . '<br>';
}

fetchAll()には、どのような形式の配列で結果を受け取るかを指定する「フェッチモード」があります。

  • PDO::FETCH_ASSOC: カラム名をキーとする連想配列で返します。最もよく使われます。
  • PDO::FETCH_NUM: 0から始まる添字の配列で返します。
  • PDO::FETCH_BOTH: 上記2つの形式を両方含んだ配列を返します。(デフォルトですが、冗長なので通常は使いません)

fetch(): 1件ずつ取得

fetch()は、結果を1行(1レコード)ずつ取得します。whileループと組み合わせて使うことで、メモリを効率的に使いながら大量のデータを処理できます。

// 結果を1行ずつ連想配列として取得し、データがなくなるまでループ
while ($review = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo htmlspecialchars($review['book_title'], ENT_QUOTES, 'UTF-8') . '<br>';
}

INSERT, UPDATE, DELETEの場合

データを登録・更新・削除する場合、**「1. 準備」→「2. 実行」**の流れは同じです。これらのSQLは結果セットを返さないため、「3. 結果取得」のステップは不要です。

代わりに、rowCount()メソッドを使って、処理の影響を受けた行数を取得することができます。

<?php
// 新しいレビューを登録するSQL
$sql = "INSERT INTO reviews (book_title, rating) VALUES (?, ?)";
$stmt = $pdo->prepare($sql);

// 実行
$stmt->execute(['PHP実践ガイド', 5]);

// 影響を受けた行数を表示
echo $stmt->rowCount() . "件のレビューを登録しました。"; // 「1件のレビューを登録しました。」
?>

PDOStatementのメソッド一覧

$pdo->prepare()が返す$stmt(PDOStatementオブジェクト)には、データベース操作に利用できる様々なメソッドが用意されています。以下にその一覧をまとめます。

メソッド説明
$stmt->bindValue()値をプレースホルダに紐付け(バインド)します。
$stmt->bindParam()変数をプレースホルダに紐付け(バインド)します。変数の値がexecute()時に評価されます。
$stmt->bindColumn()結果セットのカラムを変数に紐付けます。
$stmt->execute()準備されたプリペアドステートメントを実行します。
$stmt->fetch()結果セットから次の1行を取得します。
$stmt->fetchAll()結果セットのすべての行を含む配列を返します。
$stmt->fetchColumn()結果セットの次の行から単一のカラムを返します。
$stmt->rowCount()直前のDELETE, INSERT, UPDATE文によって作用した行数を返します。
$stmt->columnCount()結果セットに含まれるカラムの数を返します。
$stmt->setFetchMode()このステートメントのデフォルトのフェッチモードを設定します。
$stmt->closeCursor()サーバーへの接続を維持したまま、カーソルを閉じ、ステートメントを再度実行できるようにします。
$stmt->debugDumpParams()準備されたSQLコマンド文字列をデバッグ目的で出力します。
$stmt->errorCode()直近の操作で発生したSQLSTATEエラーコードを取得します。
$stmt->errorInfo()直近の操作で発生した拡張エラー情報を取得します。
$stmt->getAttribute()PDOStatementの属性を取得します。
$stmt->setAttribute()PDOStatementの属性を設定します。
$stmt->nextRowset()ストアドプロシージャから複数の結果セットを返す場合に、次の結果セットへカーソルを進めます。

まとめ

PHPとPDOでデータベースを操作する際の、安全で基本的な流れを学びました。

  • SQL文は直接実行せず、**prepare()**で準備する。
  • 変動する値は**プレースホルダ (?)にし、execute()**に配列で渡す。
  • SELECT文の結果は**fetch()またはfetchAll()**で取得する。

この**「Prepare -> Execute -> Fetch」**の作法は、SQLインジェクションを防ぎ、堅牢なWebアプリケーションを構築するための基本中の基本です。必ずこの流れをマスターしましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次