| ユーザフォーラムで議論/質問 | マニュアル検索 | ハイライト | ハイライトオフ | ポータル | php spot |
雛形への肉付け主要な構造体および属性主要な構造体である pdo_dbh_t および pdo_stmt_t については、それぞれ 付録 A および B で説明します。データベースやステートメントの属性に ついては 付録 C、エラー処理については付録 D で説明します。 pdo_SKEL.c: PHP 拡張モジュールとの橋渡し関数エントリ
この構造体は、グローバルな PHP 関数名前空間に関数を登録するために 使用されます。PDO ドライバでは、できるだけ使用を避けるべきです。 上の例で示しているように、NULL で初期化した状態にしておくことを 推奨します。 モジュールエントリ
pdo_SKEL_module_entry という名前で zend_module_entry 型の構造体を宣言し、先ほど定義した pdo_SKEL_functions テーブルへの参照を含める必要があります。 標準 PHP 拡張モジュール関数PHP_MINIT_FUNCTION
この標準 PHP 拡張モジュール関数は、ドライバを PDO に登録するために 使用されます。登録するには、php_pdo_register_driver() 関数に pdo_driver_t 型の構造体へのポインタを渡して コールします。この構造体の名前は、一般的には pdo_SKEL_driver となります。 pdo_driver_t には、マクロ PDO_DRIVER_HEADER(SKEL) を使用して生成した ヘッダおよび pdo_SKEL_handle_factory() 関数へのポインタが含まれます。実際の関数については SKEL_dbh.c の説明の中で述べます。 PHP_MSHUTDOWN_FUNCTION
この標準 PHP 拡張モジュール関数は、ドライバを PDO から登録解除する ために使用されます。解除するには、 php_pdo_unregister_driver() 関数に 上で渡したのと同じ構造体 pdo_SKEL_driver を渡してコールします。 PHP_MINFO_FUNCTIONこれもまた標準 PHP 拡張モジュール関数です。この関数の目的は、 スクリプト内で phpinfo() がコールされた際に モジュールの情報を表示することです。規約では、モジュールの バージョンおよび対応するデータベースのバージョン、そして 関連する設定情報を表示することになっています。 SKEL_driver.c: ドライバの実装このファイルでは、PDO データベースハンドルオブジェクトがサポートする すべてのデータベース処理メソッドを実装します。また、エラー情報の 取得ルーチンもここに含まれます。これらの関数では、グローバル変数 プールへのアクセスが必要になることでしょう。そのため、これらの ステートメントの最後には、Zend マクロ TSRMLS_DC を使用する必要が あります。このマクロについての詳細な情報は、Zend の プログラマ向けドキュメントを参照ください。 pdo_SKEL_error
この関数の目的は、ドライバ内での一般的なエラー処理関数として使用する
ことです。ドライバ内でエラーが発生した場合に、ドライバによって
この関数がコールされます。SQLSTATE に関連しないエラーが発生した場合、
ドライバはエラーの内容にもっとも近い SQLSTATE あるいは一般的な
SQLSTATE エラー "HY000" を、
dbh->error_code あるいは
stmt->error_code にセットする必要があります。
PDO ソース内のファイル pdo_sqlstate.c には、PDO が明示的に理解する
一般的な SQLSTATE コードのテーブルがあります。エラーコードの設定は、
この関数がコールされる前に終わっていなければなりません。この関数は、
グローバル変数
dbh メンバメソッドが NULL の場合 (PDO コンストラクタ内でエラーが 発生したことを意味します)、この関数は zend_throw_exception_ex() 関数をコールしなければなりません。それ以外の場合はエラーコードを 返します。通常、この関数はヘルパマクロを使用してコールされます。 このマクロは、データベース処理エラーおよびステートメント処理エラーの それぞれについて関数のコール手順をカスタマイズしたものです。 例1 pdo_SKEL_error をコールするマクロの例 #define pdo_SKEL_drv_error(what) \ pdo_SKEL_error(dbh, NULL, what, __FILE__, __LINE__ TSRMLS_CC) #define pdo_SKEL_drv_error(what) \ pdo_SKEL_error(dbh, NULL, what, __FILE__, __LINE__ TSRMLS_CC) エラー処理についての詳細は、エラー処理 を参照ください。
pdo_SKEL_fetch_error_func
この関数の目的は、直近に発生したエラーについての追加情報を 取得することです。ここには、ドライバ固有のエラーコードや 人間が理解できる形式のメッセージが含まれます。また、必要に応じて それ以外の追加情報も含められます。この関数は、PHP スクリプトで PDO::errorInfo() メソッドをコールした際に 呼び出されます。
error_func は、情報を 2 つの部分に分けた上で、配列の連続する要素として 返さなければなりません。最初の要素は数値形式のエラーコードで、次の 項目が文字列の説明となります。この項目を設定する方法としては add_next_index を使用するのが最適です。最初の要素の型は long である必要がないことに注意しましょう。元になるデータベース API が返すエラーコードに応じた型を選びます。 /* ここではエラー情報を追加します。 */ /* 指定した順に追加する必要があります。 */ add_next_index_long(info, error_code); /* ドライバ固有のエラーコード */ add_next_index_string(info, message, 0); /* 可読形式のエラーメッセージ */ この関数は、情報が取得可能な場合に 1、ドライバが追加情報を 保持していない場合に 0 を返します。 SKEL_handle_closer
この関数は、オープンしているデータベースを閉じるために PDO からコールされます。
オープン中のデータベースを閉じるために必要な処理は、すべてここで 済ませる必要があります。PDO は、この関数の返す値を無視します。 SKEL_handle_preparer
この関数は、PHP スクリプトで
PDO::query() および PDO::prepare()
がコールされた場合に PDO から呼び出されます。この関数の目的は、
実行する SQL を準備し、渡された
この関数は、本質的には stmt オブジェクトのコンストラクタです。 ステートメントのオプションを処理し、ドライバ固有のオプションを pdo_stmt_t 構造体に格納することがこの関数の役割となります。 prepare 関数がコールされる前に、PDO がドライバの代わりにオプションを 処理してくれることはありません。未知のオプションが渡された際に エラーを発生させるなどの処理は、あなた (ドライバ) の役割となります。 この関数の非常に重要な役割のひとつは、SQL ステートメントのパラメータを 処理することです。この関数をコールした際に、PDO は 「ドライバがプリペアドステートメントへのパラメータのバインドをサポート しているか」や「名前で指定するパラメータあるいは位置で指定するパラメータの どちらをサポートしているか」を知りません。 元となるデータベースにあわせて、ドライバが適切に stmt->supports_placeholders を設定しなければなりません。 接続先のサーバーのバージョンによってこの設定が変化するなどの理由で、 この設定を実行時に行わなければならないこともあるかもしれません。 ドライバが、名前で指定するパラメータ・位置で指定するパラメータのいすれも サポートしていない場合は、pdo_parse_params() API を使用して PDO にクエリを書き換えさせることでこの機能を サポートさせなければなりません。 例2 pdo_parse_params の使用 int ret; char *nsql = NULL; int nsql_len = 0; /* クエリを準備する前に、ちょっとその中身を確かめる必要があります。 * もし名前で指定するパラメータが用いられていれば、その処理を * PDO に任せます */ stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC); if (ret == 1) { /* クエリが書き換えられました */ sql = nsql; } else if (ret == -1) { /* 失敗しました */ strcpy(dbh->error_code, stmt->error_code); return 0; } /* "sql" の中のクエリを準備します */
supports_placeholders に指定できる値は
例3 プリペアドステートメントをネイティブにサポートしていないドライバでの実装 static int SKEL_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) { pdo_SKEL_db_handle *H = (pdo_SKEL_db_handle *)dbh->driver_data; pdo_SKEL_stmt *S = ecalloc(1, sizeof(pdo_SKEL_stmt)); S->H = H; stmt->driver_data = S; stmt->methods = &SKEL_stmt_methods; stmt->supports_placeholders = PDO_PLACEHOLDER_NONE; return 1; } この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_handle_doer
この関数は、SQL ステートメントを直接実行する際に PDO から 呼び出されます。pdo_stmt_t は作成されません。
この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_handle_quoter
この関数は、クエリで使用するために文字列をクォートする際に PDO から呼び出されます。
この関数は、
PDO::quote() がコールされた場合、
あるいはドライバが supports_placeholder
を ドライバがネイティブのプリペアドステートメントをサポートしていない場合、 この関数を実装する必要があります。 この関数は、クォート処理が正しく行われた場合や文字列を変更する必要が なかった場合に 1、文字列の変更に失敗した場合に 0 を返します。 0 が返された場合、もとの文字列がそのまま使用されます。 SKEL_handle_begin
この関数は、データベースのトランザクションを開始する際に PDO から呼び出されます。
トランザクションを開始するために必要な処理は、すべてここで 済ませる必要があります。この関数は、成功した場合に 1、 エラーが発生した場合に 0 を返します。 SKEL_handle_commit
この関数は、データベースのトランザクションを終了する際に PDO から呼び出されます。
トランザクションをコミットするために必要な処理は、すべてここで 済ませる必要があります。この関数は、成功した場合に 1、 エラーが発生した場合に 0 を返します。 SKEL_handle_rollback
この関数は、データベースのトランザクションをロールバックする際に PDO から呼び出されます。
トランザクションをロールバックするために必要な処理は、すべてここで 済ませる必要があります。この関数は、成功した場合に 1、 エラーが発生した場合に 0 を返します。 SKEL_handle_get_attribute
この関数は、データベースの属性を取得するために PDO から呼び出されます。
実装においてどの属性をサポートするかは、ドライバ次第です。ドライバは 必ずこの関数を提供しなければならないわけではありません。 PDO_ATTR_PERSISTENT、PDO_ATTR_CASE、 PDO_ATTR_ORACLE_NULLS および PDO_ATTR_ERRMODE については PDO ドライバが 直接処理します。 この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_handle_set_attributestatic int SKEL_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) この関数は、データベースの属性を設定するために PDO から呼び出されます。 通常、これはスクリプトから PDO::setAttribute() をコールした場合に発生します。
実装においてどの属性をサポートするかは、ドライバ次第です。 追加の属性をサポートする必要がないのであれば、ドライバは 必ずしもこの関数を提供しなくてもかまいません。 PDO_ATTR_CASE、 PDO_ATTR_ORACLE_NULLS および PDO_ATTR_ERRMODE については PDO ドライバが 直接処理します。 この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_handle_last_id
この関数は、最後に挿入した行の ID を取得するために PDO から 呼び出されます。
この関数は、成功した場合には最後に挿入された行の ID を含む文字列、 失敗した場合には NULL を返します。これは、オプションの関数です。 SKEL_check_liveness
この関数は、データベースとの持続的接続が現在確立されているかどうかを 調べるために PDO から呼び出されます。
この関数は、データベース接続が確立されており使用可能な状態の場合に 1、 それ以外の場合 (接続に失敗した場合や機能をサポートしていない場合など) に 0 を返します。
SKEL_get_driver_methods
この関数は、PDO あるいは PDOStatement クラスに属さないメソッドが コールされた際に PDO から呼び出されます。この関数の目的は、 ドライバ固有のメソッドをクラスに追加できるようにすることです。
この関数は、要求された function_entry テーブルへのポインタか、 ドライバ固有のメソッドが存在しない場合に NULL を返します。 SKEL_handle_factory
この関数は、データベースハンドルを作成するために PDO から呼び出されます。 ほとんどのデータベースでは、データベースへの接続がここに含まれます。 中には、持続的な接続が求められる場合もあります。あるいは接続ぷーリングが 求められる場合もあります。これらのすべては、データベース/ドライバ に依存します。
この関数は、成功した場合には、渡されたデータベースハンドル構造体に ドライバ固有の情報を格納して 1 を返し、それ以外の場合には 0 を返して 失敗したことを示します。 PDO は、handle_factory をコールする前に ドライバオプション AUTOCOMMIT および PERSISTENT を処理します。 その他のオプションを処理するのは、ハンドルファクトリの役目となります。 ドライバメソッドテーブルpdo_dbh_methods 型のスタティックな構造体を SKEL_methods という名前で 宣言し、定義された関数へのポインタでそれを初期化しておく必要があります。 関数がサポートされていなかったり実装されていなかったりする場合は、 この関数ポインタの値を NULL に設定します。 pdo_SKEL_driverpdo_driver_t 型の構造体を pdo_SKEL_driver という名前で宣言しなければ なりません。マクロ PDO_DRIVER_HEADER(SKEL) を使用して構造体の ヘッダを定義し、またハンドルファクトリ関数へのポインタを 設定しなければなりません。 SKEL_statement.c: ステートメントの実装ここでは、PDO ステートメントオブジェクトがサポートする すべてのステートメント処理メソッドを実装します。 SKEL_stmt_dtor
この関数は、事前に作成されたステートメントオブジェクトを 削除するために PDO から呼び出されます。
ステートメントのために確保したドライバ固有の領域は、すべてここで 開放する必要があります。PDO は、この関数の返す値を無視します。 SKEL_stmt_execute
この関数は、渡されたステートメントオブジェクト内のプリペアド SQL ステートメントを実行するために PDO から呼び出されます。
この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_stmt_fetchstatic int SKEL_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) この関数は、実行されたステートメントオブジェクトから行を取得するために PDO から呼び出されます。
この取得結果はドライバに依存し、データは通常 pdo_stmt_t オブジェクトの メンバ driver_data に格納されます。パラメータ ori および offset は、ステートメントがスクロール可能なカーソルを指している場合にのみ 意味を持ちます。この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_stmt_param_hook
この関数は、バインドされたパラメータやカラムを処理するために PDO から呼び出されます。
このフックは、ステートメント内でバインドされたパラメータおよびカラムの それぞれについて、個々にコールされます。ALLOC および FREE イベントは、 各パラメータあるいはカラムについて 1 度コールされます。 param 構造体は driver_data フィールドを含み、これは 各パラメータについての実装固有の情報を格納するために使用されます。 その他のすべてのイベントでは、スクリプトが PDOStatement::execute() および PDOStatement::fetch() をコールするたびに PDO からコールされることになります。 バインドされたのが変数の場合、param 構造体の is_param フラグが 設定されています。それ以外の場合は param 構造体はバインドカラムを 表します。 この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_stmt_describe_col
この関数は、特定のカラムについての情報を問い合わせるために PDO からコールされます。
ドライバは、pdo_stmt_t のメンバ columns(colno) に適切な情報を格納する 必要があります。この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_stmt_get_col_data
この関数は、指定したカラムからデータを取得するために PDO から呼び出されます。
ドライバは、結果のデータおよびその長さをそれぞれ ptr および len に 返す必要があります。メイン PDO ドライバは、データの生存期間を ドライバが管理するものと想定していることに注意しましょう。 この関数は、成功した場合に 1、失敗した場合に 0 を返します。 SKEL_stmt_set_attrstatic int SKEL_stmt_set_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) この関数は、ステートメントオブジェクトのドライバ固有の属性を 設定するために PDO から呼び出されます。
この関数はドライバに依存しており、ステートメントにデータベース固有の 属性を設定する機能を与えます。この関数は、成功した場合に 1、 失敗した場合に 0 を返します。これはオプションの関数です。 もし設定可能な追加属性をドライバがサポートしていない場合は、 メソッドテーブルで NULL を設定しておくことも可能です。PDO ドライバは、 データベースドライバに代わって設定可能属性の処理を行うことはありません。 SKEL_stmt_get_attr
この関数は、ステートメントオブジェクトのドライバ固有の属性を 取得するために PDO から呼び出されます。
この関数はドライバに依存しており、ステートメントからデータベース固有の 属性を取得する機能を与えます。この関数は、成功した場合に 1、 失敗した場合に 0 を返します。これはオプションの関数です。 もし取得可能な追加属性をドライバがサポートしていない場合は、 メソッドテーブルで NULL を設定しておくことも可能です。PDO ドライバは、 データベースドライバに代わって取得可能属性の処理を行うことはありません。 SKEL_stmt_get_col_meta
警告
この関数はうまく定義されておれず、変更する必要があります。 この関数は、指定したカラムのメタデータを取得するために PDO から呼び出されます。
ドライバの作者は、php_pdo_driver.h ヘッダに書かれているこの関数の ドキュメントを参照し、最新の情報を得てください。 この関数は、成功した場合に 1、失敗した場合に 0 を返します。 データベースドライバは、この関数を提供する必要はありません。 ステートメント操作メソッドテーブルpdo_stmt_methods 型のスタティックな構造体を SKEL_stmt_methods という名前で 宣言し、定義された関数へのポインタでそれを初期化しておく必要があります。 関数がサポートされていなかったり実装されていなかったりする場合は、 この関数ポインタの値を NULL に設定します。 |
各種マニュアル:
PHPマニュアル |
PEARマニュアル |
Smarty(英語)マニュアル |
PHP-GTKマニュアル |
「雛形への肉付け」をGoogle検索
|