PEAR DBクラスの使い方 (PHP4からPostgreSQLを利用する方法とヨタwith勘違い) -- version 0.01 -- ● はじめに:PHPからDBを使う PostgreSQLが使えるレンタルサーバに移ったので、早速PHPから使ってみようと 思いましたが、生の関数をそのまま使うのも面倒です。 そこで、DBアクセスクラスを作ろうと思いましたが、どうせ世の中にあるものを また作るのも間抜けなので既存のクラスを利用することにしました。 ・PHPLibはどうかな? PHP3のころから便利なライブラリとして、PHPLibというのが広く使われています。 セッションやDBアクセスを管理するクラスライブラリです。 ライブラリのダウンロードはこちらから(公式サイト) http://phplib.netuse.de/ 翻訳されたマニュアルはこちら http://www.php.gr.jp/php/phplib/ ・でも PHP4にはPearというものがあるのですよ。 ● Pearとは Pearライブラリは、マニュアル(http://www.php.net/manual/ja/pear.php)によ ると 「PEAR は、TeXの CTAN および Perlの CPANにヒントを得たPHP拡張および PHPラ イブラリのコード用のコードレポジトリです。 」 とのことで、これからはPHPのライブラリはPearを元に拡充しようということだ と思います。 Pearについては、PHPのマニュアルの一部になっていますし、PHPの方針としては これからはPearに違いないに違いないはずなので、Pearを使いましょう。そうしま しょう。 しかしながら、いまのところPearの利用実績はあまりないようで、情報をいまい ちありません。 特に国内ではPearに関する解説サイトが見つかりませんでした。(僕が調べた限 りなのあてになりませんが) 公式サイトのマニュアルについてもPear全体についてのコーディング規約などは 載っていますが、各クラスのリファレンスは載っていません。 どうしたものでしょう。 もっともPearのコーディング規約で、ソースコードのコメントは「phpDoc」形式 で書くことになっています。 phpDocはjavaDocのようなものでコメントからマニュアルを生成してくれます。 phpDocの公式サイトはこちら(http://www.phpdoc.de/) しかしながらphpDocでマニュアルにコンバートしたドキュメントがどこにもない のはどうしたことでしょう?(これも探し方が悪いだけかも) どちらにしても日本語でまとまった情報がないようなので、Pearを使って行くう ちに分かったことを少しずつまとめていきたいと思います。 まずはDB関連からです。 なんとなく人柱 (PHP,PostgreSQLについてあまり経験はありませんので、おそらく、相当の間違い が含まれていると思われます。お気づきの点はご指摘下さい) ● Pearの取得方法 Pearは、PHP4がインストールされていれば一緒に入っているはずです。 デフォルトでは「include_path」で指定されているディレクトリ「/usr/local/l ib/php/」にあるようです。 最新版は、CVSで取得するか、公式サイトからPHPのソースをダウンロードしてき て「pear」ディレクトリ以下を丸ごとコピーすればよいと思われます(自信なし)。 Latest version of PHP 4.0 Complete Source Code PHP 4.0.5 [2,621Kb] - 30 April 2001 http://www.php.net/downloads.php ● Pear DBクラスライブラリ データベースを操作するには、DBクラスを利用します。 DBクラスは、PHPからSQLの各種RDBMSを統一されたインターフェースでアクセス 出来るように設計されています。 だいたい次のような処理をサポートしています。 ・DBへの接続、コネクションの管理 ・DBへSQL発行 ・SQL実行結果のResultSetの取得・管理 ・ResultSetから行フェッチ ・トランザクション処理 ・エラーメッセージ処理 対応しているDBは次の通りです ・Interbase ・Mini-SQL ・Microsoft SQL Server ・MySQL ・Oracle 8 (OCI) ・ODBC ・PostgreSQL ・Sybase もっとも、各DBによってSQLの細かい構文や利用可能なフィールドは異なります ので、複数DBに対応するのは簡単な作業ではないと思います。 このドキュメントでは主にPostgreSQLの利用を前提にしています。 ● クラス概要 ┌─────┐ │DB │ └─────┘ DBへのコネクションを処理します。 接続時にDBへのインターフェースクラス(query interface = DB_???)のイン スタンスを生成します。 (DSN文字列に含まれている、DB種類指定をもとに生成するクラスを決定す る) あとは、DSN文字列の解析(parse)や、エラーメッセージ処理などを受け持っ ています。 ┌─────┐ │DB_common │ └┬────┘ │┌─────┐ ├┤DB_pgsql │ │└─────┘ │┌─────┐ ├┤DB_mysql │ │└─────┘ │ : DBへのインターフェースクラス(query interface) DB_Commonから派生しているクラスが、各DB毎の固有の処理を行っています。 これらのクラスは、ユーザーは直接インスタンスを生成せずに、DBクラスの connectメソッドにより生成します。(指定したDBのクラスのインスタンスが 生成されます。たとえば、「pgsql」を指定した場合は、DB_pgsqlクラスのイ ンスタンスが生成されます) クエリーの実行などは、このクラスに対しておこないます。 クエリーの実行結果は、レコードセットクラス(DB_result)として取得でき ます。 ┌─────┐ │DB_result │ └─────┘ クエリーの結果(レコードセット)を保持します。 レコード内容を取得できます。 レコードのフィールド定義情報、レコード数などの取得も出来ます。 ┌─────┐ │PEAR_Error│ └┬────┘ │┌─────┐ ├┤DB_Error │ │└─────┘ │┌─────┐ └┤DB_Warning│ └─────┘ DBクラス内で発生したエラー・ワーニングを保持します。 DBクラスでエラーが発生した場合は、戻り値としてDB_Errorクラスのインス タンスが返ります。 戻り値がエラーであるかどうかは、DB::isErrorメソッドで確認できます。 ワーニングの場合も同様です。 エラー処理については、Pearのエラー処理規約に準拠しているようなので、 マニュアル参照(http://www.php.net/manual/ja/class.pear-error.php)。 ● クラスリファレンス 対象バージョン: PHP 4.0.5 (Pear ver.2) 凡例: 「▼」ユーザーが直接利用するメンバ 「▽」クラス内部で利用されるメンバ (またはユーザーが直接利用するものもあるかもしれないが頻度が低そう なもの) ■ DB クラス DBへのコネクションを処理する。 インターフェースクラスのインスタンスを生成するのが主な役割。 DBクラスのインスタンスは生成する必要はない。メンバー関数は全てスタティッ ク 【メンバー変数】 無し 【メンバー関数】 ▼ &connect($dsn, $options = false) データベースへ接続する 引数: $dsn data source name $options オプション 戻り値: インターフェースクラスのインスタンス $dsnで指定されたデータソース名を元にインターフェースクラスを生成し、デー タベースへ接続する。 $dsnは、DSN文字列、または、項目毎の要素を持つArrayを指定できる。 a) DSN文字列のフォーマットは次の通り(ソースからコピー) phptype://username:password@protocol+hostspec:110//usr/db_file.db phptype://username:password@hostspec/database_name phptype://username:password@hostspec phptype://username@hostspec phptype://hostspec/database phptype://hostspec phptype(dbsyntax) phptype 例) pgsql://fukaya:password@tcp+db.fukaya.fs2.com:5432//fukaya pgsql://fukaya:password@localhost//fukaya ※ パスワードを指定していない場合は、「username:」の後に半角スペース1 文字をいれるとよい ※ パラメータ名の意味は 次項「b)」を参照 ※ DSN文字列の解析は、parseDSNメンバ関数を利用している b) dsnをArrayで指定する場合の要素は次の通り phptype データベース名("pgsql","mysql"など) dbsyntax SQLの文法 (通常はphptypeと同じ) protocol 接続に使用するプロトコル("tcp","unix"など) hostspec ホスト名 (ポートを指定する場合は、「:」で区切って指定する) ※ ローカルホストの場合は"localhost"と指定 database データベース名 ※ PostgreSQLの場合は、CreateDBコマンドで作成したDB名 username DBへログインするユーザー名 password パスワード ▼ apiVersion() APIバージョンを返す 戻り値: APIバージョン (現在は 2 ) ▼ isError($value) 指定された変数がエラークラスであるか判定する 引数: $value 判定対象の変数 戻り値: 判定結果(true:エラークラスである) DBクラス群のメンバ関数からの戻り値がエラークラス(DB_Error)であるか判定す る。 メンバ関数からの戻り値は、まずこのメソッドでエラー値であるか判定すること。 ▼ isWarning($value) 指定された変数がワーニングクラスであるか判定する 引数: $value 判定対象の変数 戻り値: 判定結果(true:ワーニングクラスである) DBクラス群のメンバ関数からの戻り値がワーニングクラス(DB_Warning)であるか 判定する。 メンバ関数からの戻り値は、まずこのメソッドでエラー値であるか判定すること。 ▼ errorMessage($value) エラーコードに対応するエラーメッセージ文字列を返す 引数: $value エラーコード 戻り値: エラーメッセージ(文字列) ▽ isManip($query) SQL文が、DML(データ操作言語)であるか判定する 引数: $query 判定対象のSQL文 戻り値: 判定結果(true:DMLである) SQL文が、DML(データ操作言語)であるか判定する。 DML(Data Manipulation Language)とはデータを操作するステートメントのこと です(INSERT,UPDATE,DELETE,REPLACEなど)。 ▽ &factory($type) インターフェースクラスインターフェースを生成する 引数: $type DB名 戻り値: インターフェースクラスのインスタンス DSNで指定されたDB名を元に、適切なインターフェースクラスを生成して返すク ラスファクトリー。 たとえば、$typeに「pgsql」を渡された場合は、DB_pgsqlクラスのインスタンス を返す。 クラス内部から利用されるユーザーが直接使用することは無い(connect関数から 利用される)。 ▽ parseDSN($dsn) DSN文字列を解析する 引数: $dsn data source name 戻り値: DNS解析結果(Array) $dsnで渡されたDSN文字列を解析して返す。 引数、戻り値の形式は、connectメンバ関数のa)、b)を参照 ▽ assertExtension($name) ■ DB_common クラス DBへのインターフェースクラスのベースクラス。 各DBの固有部分を実装したクラス(DB_pgsqlクラスなど)に派生して利用し、直接 は使用しない。 DB_pgsqlクラスでオーバーライドされているメンバは、メソッド名の右に「*」 を表記した。 機能が実装されていないメソッド(DB_ERROR_NOT_CAPABLEエラーになる)は、メ ソッド名の右に「x」を表記した。(変な表記なので後で直す) ※ DBへの接続を終了する場合は、disconnect()メソッドを使用するが、DB_common には存在せず、派生先のクラスにのみ存在する 【メンバー変数】 var $features; // assoc of capabilities for this DB implementation var $errorcode_map; // assoc mapping native error codes to DB ones var $type; // DB type (mysql, oci8, odbc etc.) var $prepare_tokens; var $prepare_types; var $prepare_maxstmt; var $error_mode = PEAR_ERROR_RETURN; var $error_level = E_USER_NOTICE; var $error_callback; var $last_query = ''; var $fetchmode = DB_FETCHMODE_ORDERED; var $options = array( 'persistent' => false, // persistent connection? 'optimize' => 'performance', // 'performance' or 'portability' ); var $dbh; 選択されたインターフェースクラス(DB_pgsql等) 【メンバー関数】 ▽ DB_common() コンストラクタ ▽ toString() 接続状態を文字列で返す 戻り値: 接続状態 ▽ quoteString($string) SQL文の「'」を「\'」に置換する 引数: $string 処理もとSQL文 戻り値: 置換後のSQL文 ▽ provides($feature) DBの機能のインプリメント状況を取得する 引数: 機能名 戻り値: true:インプリメントされている 機能名 prepare pconnect 持続的接続 transactions トランザクション ▽ errorCode($nativecode) PHPのDB操作関数からのエラーコード(ネイティブ)を、DBクラスでのエラー コードに変換する 引数: $nativecode エラーコード(ネイティブ) 戻り値: DBクラスでのエラーコード ▽ errorMessage($dbcode) PHPのDB操作関数からのエラーコード(ネイティブ)から、DBクラスでのエラー メッセージ(文字列)を返す 引数: $nativecode エラーコード(ネイティブ) 戻り値: DBクラスでのエラーメッセージ ▽ &raiseError($code = DB_ERROR, $mode = false, $level = false, $debuginfo = false, $nativecode = false) エラーを発生させる ▽ setErrorHandling($mode, $options = false) エラーハンドリングを設定 ▼ setFetchMode($fetchmode) デフォルトでのフェッチモードを指定 引数: $fetchmode フェッチモード フェッチモードを指定する。 FetchRowでレコード内のフィールドを配列で取得したときの、各要素へのアクセ ス方法 フェッチモード DB_FETCHMODE_ORDERED フィールドにはインデックスでアクセス (PostgreSQLの場合pg_fetch_row関数を使用) DB_FETCHMODE_ASSOC フォールド名でもアクセスできる (PostgreSQLの場合pg_fetch_array関数を使用) DB_FETCHMODE_FLIPPED (指定不可) ▼ setOption($option, $value) オプション値を設定する 引数: $option 項目名 $value 値 項目名 persistent true or false(default) 持続的接続をするか optimize performance(default) or portability 最適化 ▼ getOption($option) オプション設定値を取得する 引数: $option 項目名 戻り値: 項目に設定されている値 ▼ prepare($query) *x クエリーの連続(複数?)実行する際のクエリーを設定する 引数: $query クエリーのSQL文 ?よくわからない。ストアドクエリーのようなもの? 「this is emulated.」と書いてあるので、使う必要なないのか? ▼ execute($stmt, $data = false) *x prepareで設定されたクエリーを実行する ? ▼ executeEmulateQuery($stmt, $data = false) prepareで設定されたクエリーを実行する ? ▼ executeMultiple( $stmt, &$data ) prepareで設定されたクエリーを実行する ? ▽ modifyQuery($query) ネイティブのDBへ渡すためにSQLを修正する 引数: $query 修正前のSQL文 戻り値: 修正後のSQL文 いまのところ内部ではなにもしていない ▼ &query($query) * クエリー実行 引数: $query 実行するSQL文 戻り値: SQL文を実行した結果 DB_resultクラス : クエリー実行結果のResultSet DB_OK : レコードを返さないクエリーの場合 DB_Errorクラス : エラー発生時 クエリーを実行して結果(ResultSet)を取得する。 ResultSetは、DB_resultクラスとして返る。 レコードの中身を取得するのは、DB_resultクラスのメンバ関数を利用する。 一番基本的で重要なメソッド ▼ &getOne($query, $params = array()) ▼ &getRow($query, $fetchmode = DB_FETCHMODE_DEFAULT, $params = array()) ▼ &getCol($query, $col = 0, $params = array()) ▼ &getAssoc($query, $force_array = false, $params = array()) ▼ &getAll($query, $fetchmode = DB_FETCHMODE_DEFAULT, $params = array()) ? クエリー結果を一度にArrayで取得できるらしい DB_resultを介さないで済むので楽かも。 ▼ autoCommit($onoff=false) x* オートコミットの設定 引数: $onoff オートコミット(true:on false:off) デフォルトでは、ONです。 ▼ commit() x* トランザクションをコミットする ▼ rollback() x* トランザクションをロールバックする ▼ numRows($result) x* 指定ResultSetの行数を取得する 引数: $result ResultSet(ネイティブ) 戻り値: 行数 ▼ affectedRows() x* 変更された行数を取得する 戻り値: 行数 ▼ errorNative() x* ネイティブのエラーコードを返す 戻り値: エラーコード(ネイティブ) ▼ nextId($seq_name, $ondemand = true) x* シーケンスの次の値を取得する 引数: $seq_name シーケンス名 $ondemand 戻り値: 次のシーケンス値 ▼ createSequence($seq_name) x* シーケンスを作成する 引数: $seq_name シーケンス名 ▼ dropSequence($seq_name) x* シーケンスを削除する 引数: $seq_name シーケンス名 ■ DB_pgsql クラス DB_commonの派生クラス。 DB_commonのメソッドをオーバーライドしてPostgreSQL依存の部分を実装してい ます。 メンバー関数は、DB_pgsql独自のもののみ記載。 引数に$resultがあるメソッドは、DB_resultクラスから利用される。(引数の意 味はほとんど同じので、DB_resultの説明を参照して下さい) 【メンバー変数】 var $connection; pg_connect関数の戻り値 var $phptype, $dbsyntax; var $prepare_tokens = array(); var $prepare_types = array(); var $transaction_opcount = 0; var $numrows; var $row; var $affected; var $autocommit = true; var $dsn; 【メンバー関数】 ▽ DB_pgsql() コンストラクタ ▽ connect($dsn, $persistent = false) DBへ接続する 引数: $dsn DSN $persistent 持続接続するか(true:する false:しない) 戻り値: DB_OK : 成功 DB_Errorクラス : エラー DSNを元にDBへ接続する。 DSNについては、DB::connectの説明を参照。 DBクラスから呼ばれる。 ▼ disconnect() DBへの接続を終了する 戻り値: pg_closeも戻り値 ▽ simpleQuery($query) クエリーを実行する 引数: $query SQL文 戻り値: PostgreSQLネイティブのResultSetのハンドルを返す ▽ errorCode($errormsg) DBネイティブのエラーメッセージをDBクラスのエラーコードに変換 引数: $errormsg PostgreSQLのエラーメッセージ 戻り値: DBクラスのエラーコード ▽ &fetchRow($result, $fetchmode = DB_FETCHMODE_DEFAULT) ▽ fetchInto($result, &$arr, $fetchmode = DB_FETCHMODE_DEFAULT) ▽ freeResult($result) ▽ numCols($result) ▽ numRows($result) ▽ errorNative() ネイティブのエラーメッセージを取得する 戻り値: PostgreSQLのエラーメッセージ ■ DB_result クラス クエリー実行結果のRecordSetを保持するクラス 【メンバー変数】 var $dbh; var $result; ネイティブのResultSetハンドル 【メンバー関数】 ▽ DB_result(&$dbh, $result) コンストラクタ 引数: &$dbh インターフェースクラス(DB_pgsql等)への参照 $result ネイティブ関数のResultSetハンドル (postgreSQLの場合は、pg_exec関数の戻り値) DB_common::queryメソッド実行時の戻り値として、インスタンスが生成される際 に呼ばれる。 ▼ fetchRow($fetchmode = DB_FETCHMODE_DEFAULT) 現在行を取得する 引数: $fetchmode フェッチモード 戻り値: array : 現在行(レコード)のフィールド値 NULL : もう読み込むべき行がない DB_Eddorクラス : エラー 現在参照している行(レコード)のフィールド値を配列(Array)として返す。 フェッチモードにより配列のアクセス方法を指定できる。 フェッチモード DB_FETCHMODE_ORDERED フィールドにはインデックスでアクセス (PostgreSQLの場合pg_fetch_row関数を使用) 例) $row = fetchRow(DB_FETCHMODE_ORDERED); echo $row[0] . ":" .$row[1]; DB_FETCHMODE_ASSOC フォールド名でもアクセスできる (PostgreSQLの場合pg_fetch_array関数を使用) 例) $row = fetchRow(DB_FETCHMODE_ASSOC); echo $row["ID"] . ":" .$row["NAME"]; ▼ fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT) 現在行を取得する(引数で渡した配列に読み込む) 引数: &$arr レコード読み込み先の配列(Array) $fetchmode フェッチモード 戻り値: DB_OK : 現在行(レコード)の読み込み成功 NULL : もう読み込むべき行がない DB_Eddorクラス : エラー 現在参照している行(レコード)のフィールド値を指定した既存の配列(Array) に返す。 フェッチモードにより配列のアクセス方法を指定できる。 ▼ numCols() レコードの列数(フィールド数)を取得する 戻り値: レコードの列数(フィールド数)を取得する DB_Eddorクラス : エラー ▼ numRows() レコードの行数(レコード数)を取得する 戻り値: レコードの行数(フィールド数)を取得する DB_Eddorクラス : エラー ▼ free() RecordSetを開放する ● エラーコード表 DB_OK DB_ERROR DB_ERROR_SYNTAX DB_ERROR_CONSTRAINT DB_ERROR_NOT_FOUND DB_ERROR_ALREADY_EXISTS DB_ERROR_UNSUPPORTED DB_ERROR_MISMATCH DB_ERROR_INVALID DB_ERROR_NOT_CAPABLE DB_ERROR_TRUNCATED DB_ERROR_INVALID_NUMBER DB_ERROR_INVALID_DATE DB_ERROR_DIVZERO DB_ERROR_NODBSELECTED DB_ERROR_CANNOT_CREATE DB_ERROR_CANNOT_DELETE DB_ERROR_CANNOT_DROP DB_ERROR_NOSUCHTABLE DB_ERROR_NOSUCHFIELD DB_ERROR_NEED_MORE_DATA DB_ERROR_NOT_LOCKED DB_ERROR_VALUE_COUNT_ON_ROW DB_ERROR_INVALID_DSN ● 使用方法:サンプル 以下のサンプルは次の設定のデータベースが作成されていることを前提としてい ます。 データベース名 : ftdemo ユーザー名 : fukaya パスワード : (無し) ■ #01.データベースへの接続/切断 #01は、データベースへの接続および接続の終了のサンプルです。 (#01Bは参考のためのネイティブの関数を使用したサンプルです) ▼ #01.PostgreSQLへの接続/切断 (Pead DBクラス版) http://www.dokokano.com/php/ex_db01.php