ビルドする
ビルドは関数作成時とほぼ同じですが、クラス定義のために2つのファイルを登録しました。従って、config.m4ファイルにそれらのファイルをビルド対象に含めるように指定が必要になります。
PHP_ARG_ENABLE(pzip, whether to enable pzip support, Make sure that the comment is aligned: [ --enable-pzip Enable pzip support]) if test "$PHP_PZIP" != "no"; then PHP_NEW_EXTENSION(pzip, pzip.c pzip_file.c pzip_entry.c, $ext_shared) // ……(1) fi
ビルドファイルに追加するには(1)PHP_NEW_EXTENSIONの部分に作成したファイルを指定するだけです。これで一通りの準備がそろいました。いつものようにビルドをします。
$/usr/local/php-ext/bin/phpize $/configure \ --enable-pzip \ --enable-debug \ --with-php-config=/usr/local/php-ext/bin/php-config
実行に成功すれば、module/pzip.soができあがります。
実行してみる
作成されたモジュールを、クラス定義がきちんとされているかどうか、ファイルを使って確認します。
$pzip_file = new PZipFile(); // ……(1) var_dump($pzip_file); $pzip_entry = new PZipEntry(); // ……(2) var_dump($pzip_entry);
(1)、(2)のように定義したクラス名を使ってインスタンスを作成してみます。以下が実行した結果になります。
$/usr/local/php-ext/bin/php -d extension=./modules/pzip.so -f pzip.php object(PZipFile)#1 (0) { } object(PZipEntry)#2 (0) { }
エラーが表示されずに実行されれば問題ありません。
クラス定義の構造
一通りのクラス定義の流れを行ったところで、改めてやってきたことの関係を整理します。そこで、pzip.cファイルとpzip_file.cファイルの関係をクラス定義とエクステンションとしての定義の関係として図に示したものが、図1の上半分の部分になります。
これでは、モジュールにクラス定義の枠だけを登録したに過ぎません。
そして、実際のクラスの実装を行うにはプロパティ変数、コンストラクタやデストラクタ、メソッドなどがあります。ただし、ここでのコンストラクタとデストラクタはPHPでの"new"と"delete"の演算子を定義しているイメージです。実際にPHP側でdeleteを実行すると、C側のデストラクタが呼ばれます。これらを示したものが図の下半分に相当します。
この図だけではイメージがわかない部分もあると思いますが、実際のコードと照らし合わせて見ると、イメージがしやすくなるのではないでしょうか。
では、実際にそれらの実装を行っていきます。
インスタンスを管理するためのクラス定義の実装
インスタンスを作成するには、インスタンスごとのプロパティの定義と、コンストラクタ、デストラクタを定義する必要があります。
プロパティの定義
プロパティのセットを1つの構造体として管理します。ただし、ここでのプロパティはPHP側から見えるプロパティではありませんので、クラスのprivate変数を定義しているイメージの方が近いかもしれません。正確には構造体ですからモジュール内からは参照できることですが、現時点ではそのようにイメージすると理解しやすいと思います。
typedef struct _php_pzip_file{ zend_object std; // ……(1) void *zip; } php_pzip_file;
構造体の名称も、実際の構造も自由に定義できますが、(1)のようにzend_object変数だけは必要です。コンストラクタ内でこの変数を通じて、各メソッド定義内でこの構造体のインスタンスデータに対してアクセスできるように処理をします。
デストラクタの定義
コンストラクタの定義をする前にデストラクタの定義を行います。その理由はコンストラクタ内で、デストラクタとして利用する関数を指定するためです。
static void php_pzip_file_dtor(void *object TSRMLS_DC){ php_pzip_file *obj = (php_pzip_file *)object; // ……(1) if(obj->zip){ // ……(2) // 実際にはそのメモリ確保の方法に応じた解放の処理をする // efree(obj->zip); } zend_object_std_dtor(&obj->std TSRMLS_CC); // ……(3) efree(obj); // ……(4) }
(1)では、定義した構造体のポインタとして扱えるように型のキャストを行います。続いて(2)で自分で定義した変数に応じたメモリの解放処理を行います。今回のサンプル内では、実際のメモリ確保は行いませんので、ここで処理が行われることはありませんが、この処理を忘れるとメモリリークが発生します。ライブラリ特有のメモリ確保などを行っている場合には、PHP側でメモリ取得を把握しておりませんので、PHP側が自動で処理をすることはありませんので、十分に注意が必要です。
次に(3)では必要な終了処理を自動的に処理し、(4)で構造体データの解放をします。この2つの処理はいずれのクラス定義でも同じ流れになります。