PHP 拡張モジュールのソースファイルの中には、
C プログラマにとって目新しいものがいくつか含まれています。
これらの中でも最も重要であり、
拡張モジュールを開発するにあたって最初にさわることになるのが
zend_module
構造体です。
この構造体には豊富な情報が格納されており、
その拡張モジュールの依存性やバージョン、コールバック、
その他重要なデータを Zend Engine に伝える役割を果たします。
この構造体の中身は、何度も大幅に変更されています。
ここでは、PHP 5.2 の時点の情報をもとにして説明します。
PHP 5.3 では少々変更されている点もあります。
counter.c での zend_module
の宣言は、次のようになります。これは、
ext_skel --extname=counter
で生成したものをもとにして、既に存在しないいくつかの構造体を削除したものです。
例1 counter 拡張モジュールにおける zend_module の宣言部
/* {{{ counter_module_entry */ zend_module_entry counter_module_entry = { STANDARD_MODULE_HEADER, "counter", counter_functions, PHP_MINIT(counter), PHP_MSHUTDOWN(counter), PHP_RINIT(counter), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(counter), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(counter), "0.1", /* Replace with version number for your extension */ STANDARD_MODULE_PROPERTIES }; /* }}} */
最初はちょっとひるむかも知れませんが、
大半の部分はよく見れば非常に単純です。
次に示すのは、PHP 5.3 の zend_modules.h
における zend_module
の宣言部です。
例2 PHP 5.3 における zend_module の定義
struct _zend_module_entry { unsigned short size; unsigned int zend_api; unsigned char zend_debug; unsigned char zts; const struct _zend_ini_entry *ini_entry; const struct _zend_module_dep *deps; const char *name; const struct _zend_function_entry *functions; int (*module_startup_func)(INIT_FUNC_ARGS); int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); int (*request_startup_func)(INIT_FUNC_ARGS); int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); const char *version; size_t globals_size; #ifdef ZTS ts_rsrc_id* globals_id_ptr; #else void* globals_ptr; #endif void (*globals_ctor)(void *global TSRMLS_DC); void (*globals_dtor)(void *global TSRMLS_DC); int (*post_deactivate_func)(void); int module_started; unsigned char type; void *handle; int module_number; };
これらのフィールドの多くは、決して拡張モジュールの作者が触ることはありません。
数多くのマクロが標準で用意されており、
そのマクロが適切な値を自動的に設定します。
STANDARD_MODULE_HEADER
マクロは、
deps フィールドまでのすべての内容を埋めます。
一方 STANDARD_MODULE_HEADER_EX
は
deps フィールドを空のままにしておき、
開発者が使えるようにします。name から
version までのすべてのフィールドは、開発者が設定する必要があります。
その後、STANDARD_MODULE_PROPERTIES
マクロで構造体の残りのフィールドを埋めます。あるいは
STANDARD_MODULE_PROPERTIES_EX
マクロを使用すると、
extension global と post-deactivation function のフィールドを空のままにします。
いまどきの拡張モジュールのほとんどは、モジュールグローバルを使用します。
注意:
ショートカットマクロに頼らず、構造体のフィールドをすべて自分で設定したい場合は、 この表の値を使用します。 これはお勧めしません。 そのフィールドの "正しい" 値は変わる可能性があります。 可能な限りマクロを使用するようにしましょう。
フィールド | 値 | 説明 |
---|---|---|
size [1] [2] [3] | sizeof(zend_module_entry) |
この構造体の大きさ (バイト数)。 |
zend_api [1] [2] [3] | ZEND_MODULE_API_NO |
モジュールをコンパイルした Zend API のバージョン。 |
zend_debug [1] [2] [3] | ZEND_DEBUG |
モジュールがデバッグモードでコンパイルされていることを示すフラグ。 |
zts [1] [2] [3] | USING_ZTS |
モジュールが ZTS (TSRM) を有効にしてコンパイルされていることを示すフラグ (メモリ管理 を参照ください)。 |
ini_entry [1] [3] | NULL |
このポインタは Zend の内部で用い、 モジュールで宣言した非ローカルの INI エントリへの参照を保持します。 |
deps [3] | NULL |
モジュールの依存性一覧へのポインタ。 |
name | "mymodule" | モジュールの名前。これは "spl" あるいは "standard" のような短い名前です。 |
functions | mymodule_functions | モジュールの関数テーブルへのポインタ。 Zend は、これを使用してモジュール内の関数をユーザー空間に公開します。 |
module_startup_func | PHP_MINIT(mymodule) | コールバック関数です。Zend は、特定の PHP インスタンスで そのモジュールが最初にロードされるときにこれをコールします。 |
module_shutdown_func | PHP_MSHUTDOWN(mymodule) | コールバック関数です。Zend は、特定の PHP インスタンスから そのモジュールがアンロードされるとき (通常は最後のシャットダウン時) にこれをコールします。 |
request_startup_func | PHP_RINIT(mymodule) |
コールバック関数です。Zend は、各リクエストの開始時にこれをコールします。
これは、可能な限り短くするか NULL にしておかなければなりません。
リクエストのたびにこれをコールするコストがかかるからです。
|
request_shutdown_func | PHP_RSHUTDOWN(mymodule) |
コールバック関数です。Zend は、各リクエストの終了時にこれをコールします。
これは、可能な限り短くするか NULL にしておかなければなりません。
リクエストのたびにこれをコールするコストがかかるからです。
|
info_func | PHP_MINFO(mymodule) | コールバック関数です。Zend は、phpinfo() 関数がコールされたときにこれをコールします。 |
version | NO_VERSION_YET |
モジュールのバージョンを表す文字列。モジュールの作者が指定したものです。 バージョン番号の形式は、 version_compare() に対応したもの (たとえば "1.0.5-dev") か CVS や SVN のリビジョン番号 (たとえば "$Rev: 324071 $") にあわせたものにしておくことを推奨します。 |
globals_size [1] [4] [5] [6] | sizeof(zend_mymodule_globals) | このモジュール用のグローバル構造体が存在する場合のサイズ。 |
globals_id_ptr [1] [4] [5] [6] [7] | &mymodule_globals_id |
定数 USING_ZTS が TRUE かどうかによって、
これらふたつのフィールドのうちのいずれかひとつだけが存在します。
最初のほうはモジュールのグローバル用の TSRM アロケーションテーブルへのインデックス、
後のほうはグローバルへの直接のポインタとなります。
|
globals_ptr [1] [4] [5] [6] [8] | &mymodule_globals | |
globals_ctor [4] [5] [6] | PHP_GINIT(mymodule) | この関数は module_startup_func の 前に コールされ、モジュールのグローバルを初期化します。 |
globals_dtor [4] [5] [6] | PHP_GSHUTDOWN(mymodule) | この関数は module_shutdown_func の 後に コールされ、モジュールのグローバルを破棄します。 |
post_deactivate_func [4] | ZEND_MODULE_POST_ZEND_DEACTIVATE_N(mymodule) | この関数は、リクエストの終了処理の後で Zend からコールされます。 めったに使われることはありません。 |
module_started [1] [9] [4] | 0 | これらのフィールドは、Zend の内部管理用の情報を扱うために使用します。 |
type [1] [9] [4] | 0 | |
handle [1] [9] [4] | NULL |
|
module_number [1] [9] [4] | 0 | |
[1]
このフィールドは、モジュール開発者が使うものではありません。
[2]
このフィールドは
STANDARD_MODULE_HEADER_EX が設定します。
[3]
このフィールドは
STANDARD_MODULE_HEADER が設定します。
[4]
このフィールドは
STANDARD_MODULE_PROPERTIES が設定します。
[5]
このフィールドは
NO_MODULE_GLOBALS が設定します。
[6]
このフィールドは
PHP_MODULE_GLOBALS が設定します。
[7]
このフィールドが存在するのは
USING_ZTS が TRUE
のときだけです。
[8]
このフィールドが存在するのは
USING_ZTS が FALSE
のときだけです。
[9]
このフィールドは
STANDARD_MODULE_PROPERTIES_EX が設定します。
|
これだけ多くのフィールドがあると、
どれが何のためのものなのかがなかなかわかりにくいものです。
ここで、サンプルの "counter" 拡張モジュールにおける
zend_module
の定義の最終形を見てみましょう。
例3 Counter 拡張モジュールの定義
/* {{{ counter_module_entry */ zend_module_entry counter_module_entry = { STANDARD_MODULE_HEADER, "counter", counter_functions, PHP_MINIT(counter), PHP_MSHUTDOWN(counter), PHP_RINIT(counter), PHP_RSHUTDOWN(counter), PHP_MINFO(counter), NO_VERSION_YET, PHP_MODULE_GLOBALS(counter), PHP_GINIT(counter), PHP_GSHUTDOWN(counter), NULL, STANDARD_MODULE_PROPERTIES_EX }; /* }}} */
STANDARD_MODULE_HEADER
を使用します。
NO_VERSION_YET
は、そのモジュールにバージョンがないことを
Zend に教えてあげるうまいやりかたです。実際に使用するモジュールの場合は、
この部分には "1.0"
などを入れることになるでしょう。
PHP_MODULE_GLOBALS
を使用しています。
NULL
を指定しています。
STANDARD_MODULE_PROPERTIES_EX
を使用しています。
何もありません。
PHP 5.2 と PHP 5.3 での zend_module
構造体の唯一の違いは、いくつかの const キーワードだけです。