PHPでデータベースにアクセスする方法のうち、今回はPDO (PHP Data Objects)によって行う方法を紹介します。PDOをサポートしているデータベース(DB)を用いると、接続の時にその種類を指定する以外は、PDOによって統一化された方法でアクセスすることができます。関数の場合は接続するデータベースの種類ごとに関数名が変わりますが、PDOでは多くの機能がPDOクラスに集約され、各DBごとに特化したメソッドや定数についてのみ、DBの種類に応じた名称がつけられています。
PDOを利用するための設定
PDOを利用できるようにするには、事前に確認しておかなくてはならないことがあります。
接続するDBに対応したPDO用のドライバが用意されているか
ドライバとは、PDOによる接続を行うモジュールで、それぞれのDBMSごとに必要です。Oracle, PostgreSQLなど主なDBでは、あらかじめ用意されていることが多いですが、PHPプログラムがそれを利用可能になっているかは、php.iniという設定ファイルの内容を確認する必要があります。
本稿で用いるPostgreSQLの場合は、リスト1 の設定をphp.iniに追加しなくてはなりません。行頭に;(セミコロン)がついている場合はセミコロンを削除します。
リスト1 php.iniの設定(Windows版PHPの場合)
extension=php_pdo.dll
extension=php_pdo_pgsql.dll
PHPでPDOが利用可能になっているか
これはDBアクセスを行うPDOというクラスをPHPプログラム内で利用できるかどうかということです。PHPの言語処理系をソースコードからコンパイルする時には、PDOを利用可能にするオプションを設定しなくてはなりません。詳細はオンラインマニュアル を参照してください。
PDOによるDBの接続と切断
前述しましたが、PDOによってDB接続を行うにはPDOというクラスを用います。クラスとは、プログラム内で扱うデータの型を新たに定義したものです。これによってオブジェクト指向という考え方に基づいたプログラミングを可能にします。
DB接続する場合は、それを表す変数に対してPDOインスタンスを代入します。インスタンスとは、クラスによって定義された型に対して、実際に処理するデータを当てはめたものです。ここでいうデータは、接続するDBを表す文字列、ユーザ名、パスワードなどです。
DBアクセスが終了し、切断する場合は、接続に用いた変数をunset関数により開放します。単にnullを代入するだけでもDBから切断できます。
リスト2 にDBの接続と切断を行う例を示します。一連の処理を try {...} catch() {...} で囲んでいるところがポイントです。
リスト2 DBへの接続と切断の例
try {
$db = new PDO( 'pgsql:host=localhost port=5432 dbname=postgres', 'postgres', 'postgres' );
/* ..... DBアクセス ..... */
unset( $db );
} catch( PDOException $ex ) {
print 'アクセスできません : ' . $ex->getMessage();
unset( $db );
die();
}
try {...} catch() {...} は、 try {...} 内の処理でエラーが発生して例外がスロー(throw)されたことを察知すると、自動的に catch() {...} の処理を行うというものです。察知可能な例外の種類は catch() の()内で指定します。複数の例外を察知できるようにするには、その種類ごとに catch() が必要です。
ここでは() 内でPDOに関連した例外を表す PDOException が指定されていますので、 catch() {...} 内の処理はPDOException、およびそれを継承した例外がスローされた時に実行されることになります。
SQLをすぐに実行する
関数でSQLをすぐに実行する時はpg_query関数(PostgreSQLの場合)を用いるのでした。このときPDOではqueryメソッドを用います。SELECT文を実行する例をリスト3 に示します。この中で$rowはSELECTの実行結果を1行ずつ読み込むために用いる変数です。なお、SELECT文中のbookmarkテーブルについては前回を参照してください。
リスト3 SQL(SELECT文)を実行する例
$db = new PDO( ... );
foreach( $db->query( 'SELECT * FROM bookmark ORDER BY id' ) as $row ) {
$title = mb_convert_encoding( $row[ 'title' ], 'SJIS', 'UTF-8' );
print 'id = ' . $row[ 'id' ] . ', title = ' . $title . ', url = ' . $row[ 'url' ] . "\n";
}
$db->query()は、PDOインスタンスが持つqueryメソッドを実行するという意味です。クラスには、実際の処理に用いるデータであるプロパティ(property)と、データを用いた処理を行うメソッド(method)とが同じクラスメンバとしてまとめられています。
メソッドは関数と同じように、必要な引数を設定して実行すると、結果を表す戻り値を受け取ることができます。queryはそのメソッドのうちの1つで、接続されたDBに対して、()内に記述されたSQL文を実行する処理を行います。
SQLを準備する
関数で実行するSQLを準備するにはpg_prepare関数(PostgreSQLの場合)を用いるのでした。PDOではprepareメソッドを用います。その例をリスト4 に示します。このとき$stmtにはPDOStatementインスタンスが代入されます。
リスト4 prepareの使用例
$stmt = $db->prepare( 'INSERT INTO bookmark( title, url ) VALUES ( :title, :url )' );
準備したSQLにパラメータを設定して実行
prepareメソッドによって準備されたSQLには、パラメータを設定できます。以下に4通りの方法を示します。
a.配列(array)で名前付きプレースホルダにパラメータを当てはめて実行
$stmt->execute( array( ':title' => $title, ':url' => $url ) );
上記で準備したSQL(INSERT文)には、実際にDB追加されるデータとして :title, :url を記述しています。これらは名前付きプレースホルダといいます。この部分はSQL文の実行時に、配列を用いて実際のデータに置き換えられます。
b.bindParamメソッドで名前付きプレースホルダにパラメータを当てはめる
$stmt = $db->prepare( 'INSERT INTO bookmark( title, url ) VALUES ( :title, :url )' );
$stmt->bindParam( ':title', $title, PDO::PARAM_STR, 100 );
$stmt->bindParam( ':url', $url, PDO::PARAM_STR, 200 );
$stmt->execute();
配列ですべてのパラメータを一括して設定できない場合は、bindParamメソッドで1つずつデータを置き換えていき、必要なパラメータをすべて設定できた時点ではじめて実行することもできます。
PDO::PARAM_STRは、このパラメータをDB側では文字列型のデータとして受け取ってもらうように設定することを表します。後に続く数値は文字列の長さです。これらは一部の場合を除いて省略することもできます。
c.配列を用いて ? で表されたプレースホルダの順にパラメータを当てはめて実行
$stmt = $db->prepare( 'INSERT INTO bookmark( title, url ) VALUES ( ?, ? )' );
$stmt-<execute( array( $title, $url ) );
プレースホルダは ?
で記述することもできます。この場合はSQL文中の先頭に近い ?
から順に配列の要素をパラメータとして当てはめてからSQL文を実行します。
d.bindParamメソッドで ? で表されたプレースホルダの位置を表す番号でパラメータを当てはめる
$stmt = $db->prepare( 'INSERT INTO bookmark( title, url ) VALUES ( ?, ? )' );
$stmt->bindParam( 1, $title );
$stmt->bindParam( 2, $url );
$stmt->execute();
プレースホルダが?
の場合でも、bindParamメソッドは実行できます。どの ?
にパラメータを当てはめるかは、文字列の先頭から数えた ?
の位置で設定します。位置は最も先頭に近い ?
が1、それ以降2, 3... となります。
クラスとメソッドのおさらい
今回用いたクラスとメソッドを表1 に示します。newはメソッドではないのですが、決まり文句の1つとして一緒に掲げておきます。データベースの種類が違っていても、ほとんどのアクセス方法は同じですから、それぞれの実行環境で試してみてください。
クラスやメソッドの詳細は、PHPマニュアルなどを参照してください。
表1 今回用いたメソッドなど
PDOクラス
new PDO(...)
データベースに接続(※newは演算子)
query
SQLをすぐに実行する
PDOStatementクラス
prepare
実行するSQLを準備する
bindParam
SQLにパラメータを当てはめる
execute
パラメータを当てはめたSQLを実行する
PDOExceptionクラス
getMessage
エラーメッセージを参照