PHP 拡張モジュールのソースファイルの中には、 C プログラマにとって目新しいものがいくつか含まれています。 これらの中でも最も重要であり、 拡張モジュールを開発するにあたって最初にさわることになるのが zend_module 構造体です。 この構造体には豊富な情報が格納されており、 その拡張モジュールの依存性やバージョン、コールバック、 その他重要なデータを Zend Engine に伝える役割を果たします。 この構造体の中身は、何度も大幅に変更されています。 ここでは、PHP 5.0 の時点の情報をもとにして説明します。 PHP 5.1 や 5.2、5.3 では少々変更されている点もあります。
example.c での zend_module の宣言は、次のようになります。これは、 ext_skel --extname=example で生成したものをもとにして、既に存在しないいくつかの構造体を削除したものです。
Example#1 example 拡張モジュールにおける zend_module の宣言部
/* {{{ example_module_entry
*/
zend_module_entry example_module_entry = {
STANDARD_MODULE_HEADER,
"example",
example_functions,
PHP_MINIT(example),
PHP_MSHUTDOWN(example),
PHP_RINIT(example), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(example), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(example),
"0.1", /* Replace with version number for your extension */
STANDARD_MODULE_PROPERTIES
};
/* }}} */
最初はちょっとひるむかも知れませんが、 大半の部分はよく見れば非常に単純です。 次に示すのは、PHP 5.3 の zend_modules.h における zend_module の宣言部です。
Example#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);
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
footnote
このフィールドは、モジュール開発者が使うものではありません。 /footnote footnoteこのフィールドは STANDARD_MODULE_HEADER_EX が設定します。 /footnote footnoteこのフィールドは STANDARD_MODULE_HEADER が設定します。 /footnote |
sizeof(zend_module_entry) |
この構造体の大きさ (バイト数)。 |
| zend_api footnoteref footnoteref footnoteref | ZEND_MODULE_API_NO | モジュールをコンパイルした Zend API のバージョン。 |
| zend_debug footnoteref footnoteref footnoteref | ZEND_DEBUG | モジュールがデバッグモードでコンパイルされていることを示すフラグ。 |
| zts footnoteref footnoteref footnoteref | USING_ZTS | モジュールが ZTS (TSRM) を有効にしてコンパイルされていることを示すフラグ (メモリ管理 を参照ください)。 |
| ini_entry footnoteref footnoteref | NULL | このポインタは Zend の内部で用い、 モジュールで宣言した非ローカルの INI エントリへの参照を保持します。 |
| deps footnoteref | 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 は、各リクエストの開始時にこれをコールします。 |
| request_shutdown_func | PHP_RSHUTDOWN(mymodule) | コールバック関数です。Zend は、各リクエストの終了時にこれをコールします。 |
| info_func | PHP_MINFO(mymodule) | コールバック関数です。Zend は、phpinfo() 関数がコールされたときにこれをコールします。 |
| version | NO_VERSION_YET | モジュールのバージョンを表す文字列。モジュールの作者が指定したものです。 バージョン番号の形式は、 version_compare() に対応したもの (たとえば "1.0.5-dev") か CVS や SVN のリビジョン番号 (たとえば "$Rev$") にあわせたものにしておくことを推奨します。 |
|
globals_size
footnoteref
footnote
このフィールドは STANDARD_MODULE_PROPERTIES が設定します。 /footnote footnoteこのフィールドは NO_MODULE_GLOBALS が設定します。 /footnote footnoteこのフィールドは PHP_MODULE_GLOBALS が設定します。 /footnote |
sizeof(zend_mymodule_globals) | このモジュール用のグローバル構造体が存在する場合のサイズ。 |
|
globals_id_ptr
footnoteref
footnoteref
footnoteref
footnoteref
footnote
このフィールドが存在するのは USING_ZTS が TRUE のときだけです。 /footnote |
&mymodule_globals_id | 定数 USING_ZTS が TRUE かどうかによって、 これらふたつのフィールドのうちのいずれかひとつだけが存在します。 最初のほうはモジュールのグローバル用の TSRM アロケーションテーブルへのインデックス、 後のほうはグローバルへの直接のポインタとなります。 |
|
globals_ptr
footnoteref
footnoteref
footnoteref
footnoteref
footnote
このフィールドが存在するのは USING_ZTS が FALSE のときだけです。 /footnote |
&mymodule_globals | |
| globals_ctor footnoteref footnoteref footnoteref | PHP_GINIT(mymodule) | この関数は module_startup_func の 前に コールされ、モジュールのグローバルを初期化します。 |
| globals_dtor footnoteref footnoteref footnoteref | PHP_GSHUTDOWN(mymodule) | この関数は module_shutdown_func の 後に コールされ、モジュールのグローバルを破棄します。 |
| post_deactivate_func footnoteref | ZEND_MODULE_POST_ZEND_DEACTIVATE_N(mymodule) | この関数は、リクエストの終了処理の後で Zend からコールされます。 めったに使われることはありません。 |
|
module_started
footnoteref
footnote
このフィールドは STANDARD_MODULE_PROPERTIES_EX が設定します。 /footnote footnoteref |
0 | これらのフィールドは、Zend の内部管理用の情報を扱うために使用します。 |
| type footnoteref footnoteref footnoteref | 0 | |
| handle footnoteref footnoteref footnoteref | NULL | |
| module_number footnoteref footnoteref footnoteref | 0 |
これだけ多くのフィールドがあると、 どれが何のためのものなのかがなかなかわかりにくいものです。 ここで、実際のサンプル拡張モジュールにおける zend_module の定義を見てみましょう。 この拡張モジュールは、カウンタ機能を提供するものです。 カウンタの現在値を取得する関数がコールされるたびに、カウンタの値がひとつ増えます。 カウンタをリセットする方法については INI スイッチで制御します。 なんだか実際にはあまり役に立たなさそうですが、 拡張モジュールの作成時に使用するテクニックをたくさん紹介するためにこうしています。
Example#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
};
/* }}} */