基本構造

C 言語は、非常に低レベルなレイヤーを今風に扱えるようにした言語です。 PHP のように組み込みでさまざまな機能が用意されているわけではありません。 リフレクションや動的モジュール読み込み、範囲チェック、 スレッドセーフなデータ管理、さまざまなデータ構造 (リンクリストやハッシュテーブルなど) は組み込みの機能としては用意されていません。 と同時に、C 言語はプログラミング言語としての一般的な機能はすべて兼ね備えています。 それなりに努力しさえすれば、先ほどあげた内容はすべて実現可能です。 実際、Zend Engine ではこれらをすべて利用することができます。

Zend API を、拡張しやすくかつわかりやすいものにするためにさまざまな努力を重ねてきました。 しかし、C 言語はどんな拡張に対しても何らかの宣言が必要となるものであり、 不慣れな人が見ると冗長に感じたり説明不足に感じたりすることは避けられません。 これから説明していくこれらの言語構造は、Zend Engine 2 や 3 においては "一度書いたらあとは忘れてしまってよい" ものです。 ここで示すのは、PHP 5.3 の ext_skel で生成したファイル php_counter.h および counter.c の抜粋です。どのような宣言が生成されるのかをごらんください。

注意: 勘のいい方ならお気づきでしょうが、 実際のファイルにはここであげた以外にもいくつかの宣言があります。 これらの宣言は Zend サブシステム群に固有のものであり、 ここで説明するのは適切ではありません。

extern zend_module_entry counter_module_entry;
#define phpext_counter_ptr &counter_module_entry

#ifdef PHP_WIN32
#    define PHP_COUNTER_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#    define PHP_COUNTER_API __attribute__ ((visibility("default")))
#else
#    define PHP_COUNTER_API
#endif

#ifdef ZTS
#include "TSRM.h"
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_counter.h"

/* ... */

#ifdef COMPILE_DL_COUNTER
ZEND_GET_MODULE(counter)
#endif
  • counter_module_entry の行では、 グローバル変数とそれを指すポインタのマクロを宣言しています。 ここにはその拡張モジュール用の zend_module_entry が格納されます。 後で説明するように "真の" グローバル変数には弱点もありますが、 ここでの使用は意図的なものです。 この変数を誤用しないよう、Zend では予防措置を行っています。
  • PHP_COUNTER_API は、PHP 以外の関数から使用するために宣言しているものです。 他のモジュールから使わせるためにエクスポートすることを想定しています。 counter 拡張モジュールではこれを宣言していないので、 最終版のヘッダファイルではこのマクロを取り除きます。 PHPAPI マクロは完全に別の場所で宣言されており、 標準のモジュールが phpinfo() 関数を実行する際に使用します。
  • PHP あるいは拡張モジュールをスレッドセーフ環境でコンパイルしない場合は TSRM は使用しません。そのため TSRM.h のインクルードは不要です。
  • 標準のインクルードファイル群として、特にその拡張モジュール自身の php_counter.h が存在します。 config.h は、configure が決定した結果にアクセスできるようにするものです。 php.h は、 PHP や Zend API との橋渡しを担当します。 php_ini.h は、実行時設定 (INI) エントリ用の API を追加します。 すべての拡張モジュールがこれを使うというわけではありません。 最後に、ext/standard/info.h が上記の phpinfo() API をインポートします。
  • COMPILE_DL_COUNTERconfigure で定義されるのは、counter 拡張モジュールが有効になっており、 かつ PHP への静的リンクではなく動的ロードモジュールとしてビルドする場合のみです。 ZEND_GET_MODULE で定義するちょっとした関数を使用して、 Zend はその拡張モジュールの zend_module_entry を実行時に取得します。

    注意: counter モジュールを静的にビルドしようとして main/php_config.h を調べた人の中には HAVE_COUNTER という定数が定義されていることにお気づきのかたもおられるかもしれません。 この定数はソースコードのどこでも用いられていません。 理由は簡単で、このチェックは行われないからです。 このチェックは不要なのです。 拡張モジュールが有効になっていなければ、 そのファイルがコンパイル対象となることはないからです。