TOP書籍連動> プリペアードステートメント
PDOの紹介
PDOの紹介

第4回:データの検索とその他機能の紹介

著者:Ilia Alshanetsky   2005/12/28
前のページ  1  2   3  次のページ
プリペアードステートメント

   PDOで使用可能な便利な機能として、次にプリペアードステートメントを紹介します。プリペアードステートメントはデータベースそのものに実装されているかどうかという問題はありますが、PDOのコア機能の1つです。

   セキュリティとアプリケーションのパフォーマンスの両方を改善する強力な機能です。プリペアードステートメントはクエリの解析処理と実行を分割して行います。

   例えば、query()メソッドでSQLを直接実行するときには、毎回データベースはクエリを解析してから実行します。クエリの解析処理は一瞬で終わりますが、同じようなクエリを複数回に渡って実行する場合は、多少の時間はかかります。

   プリペアードステートメントでは、クエリは動的なトークン以外の部分が前もって解析処理されます。生成されるステートメントは何回でも再利用することができます。そのため、ステートメントの実行時には動的なトークンの部分を実際に割り当てられた値に置換するだけで、クエリの解析処理は行われることがなくなります。

   セキュリティ上の利点としては、トークンがクエリの一部として扱われることがなくなるので、単なるSQL上の変数としてトークンを扱うことができます。そのため、SQLインジェクションの危険性を排除することができ、quote()メソッドを使用して変数をエスケープする必要もなくなるので、この部分で多少はパフォーマンスも改善されます。

   PDOでプリペアードステートメントを使用するのは簡単で、2ステップの処理を記述するだけです。まずはprepare()メソッドを使用して、SQLクエリからステートメントを生成します。

$stmt = $db->prepare("INSERT INTO foo (a,b) VALUES(?,?)");

   クエリに変数を含ませたい場合は、上記のように変数に置き換えたい部分を「?」とするか、下記の例のように簡単に理解できるように名前を付けることもできます。

$stmt = $db->prepare("INSERT INTO foo (a,b) VALUES(:a, :b)");

   クエリの解析処理に成功すると、SQLを実行するために使用するPDOStatementオブジェクトが返されます。実際のクエリの実行は、execute()メソッドで実現されます。

   このとき、解析処理されたクエリのトークンと置換する値を格納した配列の引数をオプションで指定することができます。配列の要素数はクエリの中のトークの数と同じになっていなければなりません。名前の付いていないトークンが使用される場合は、パラメータの配列はシンプルな1次元の配列で、それぞれの要素がトークンに置換されます。

$stmt->execute(array(1,2));

   名前付きのトークンを使用する場合は、「:」の文字を含んだ完全なトークン名がキーとなっている連想配列を指定します。連想配列の値は置換される値になります。

$stmt->execute(array(':a'=>1, ':b'=>2));

   トークンを変数にバインドすると、execute()メソッドを実行するたびに配列を作成する必要がなくなります。これはCSVファイルなどの外部ソースから取得した値が変数に格納されている場合は、特に効果を発揮するでしょう。

$stmt = $db->prepare("INSERT INTO users (name, email) VALUES(?, ?)");
$stmt->bindParam(1, $name, PDO_PARAM_STR,255);
$stmt->bindParam(2, $login, PDO_PARAM_STR,32);

   bindParam()メソッドは変数と位置が指定されたトークンを関連付けます。ここでも注意が必要ですが、指定する数字は0ではなく1からはじまります。バインドされたそれぞれの変数には、データベースでのデータ型を指定するための定数を指定する必要があります。

   文字列を指定する場合は必須ではありませんが、データベース内部の処理を最適化するために文字列の最大長を指定することが推奨されます。変数がバインドされると以下のように、CSVファイルから取得できる値を変数に保存し、execute()メソッドを呼び出すだけで、正しい値が入ったSQLが実行されます。

$fp = fopen("users.csv", "r");
while ($csv = fgetcsv($fp, 1024)) {
     list(,$name,$email,) = $csv;
     $stmt->execute();
}

   プリペアードステートメントはテーブルの作成および修正のクエリを除いた、すべてのクエリで使用することができます。SELECT文の場合は先ほど見たexecute()メソッドの部分をfetch()メソッドとすることでデータを取得できます。

   すべてのデータベースシステムがプリペアードステートメントをサポートしているわけではなく、PDOでサポートしているプリペアードステートメントに関する機能が完全にはサポートされていないこともあります。

   そのような場合は、PDOの内部でエミュレーションを行い、データベースごとに問題となる機能を補間します。例えば、MySQLドライバの場合、プリペアードステートメントはバージョン4.1.3以降でのみ使用可能ですが、それよりも古いバージョンでもエミュレーションによってPDOのプリペアードステートメントの機能を使用することができます。

   PostgreSQLでプリペアードステートメントを使用する場合は、クエリの実行計画の最適化に失敗してパフォーマンスが低下してしまうことがあります。このため、"PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT"という属性が、データベースのネイティブな機能を使用しないでエミュレーションを強制的に行うために追加されています。

前のページ  1  2   3  次のページ


Ilia Alshanetsky
著者プロフィール
Ilia Alshanetsky
PHP開発チームの活動メンバーの1人であり、現在のPHP 4.3.X.のリリースマネージャー。また、オープンソース掲示板FUDフォーラム(http://fud.prohost.org/forum/)をはじめとする数多くのプロジェクトにも貢献している。


INDEX
  バインドメカニズム
プリペアードステートメント
  ユーティリティ関数