対象読者
PHPでの基本構文を理解している方で、PHPエクステンションに興味がある方、さらに深くPHPを知りたい方で、C言語の基本的な構文を理解している方を対象としています。
必要な環境
この記事では、PHP 5.4を使用し、Linux環境で確認を行っています。インストール方法は初回を参照してください。
作成するクラスの概要
クラス定義の全体像を紹介する前に、実際に簡単なクラスの作成方法を通じて手順を紹介します。よりイメージしやすいように、Zipアーカイブを扱うクラスを想定して作成します。しかしながら、まだ何のメソッドもありません。これをPHPで作成してみた場合のイメージを以下に示します。
// Zipアーカイブファイルを扱うクラスを想定 class PZipFile{ } // Zipアーカイブファイル中の一つのファイル(データ)を扱うクラスを想定 class PZipEntry{ }
好みに左右される部分もありますが、より一般的なクラス管理に近いように、1つのクラス作成ごとに1つのファイルで実装をします。クラスは2つほどありますので、2つのファイルを作成します。もし、2つ以上のクラスを作成することになったとしても、同様の方法で追加していけば問題ありません。では、実際にエクステンションの作成を行います。
クラス作成の手順
PHPであれば、空のクラスを作成する処理はほんの2行で終わってしまいますが、エクステンションとなるとそうはいきません。とはいえ一度流れを覚えてしまえば、記述コードは多いものの、ほとんどのクラス作成で共通です。ここで間違えると後々面倒になるので、復習の意味もかねてモジュールの作成からビルド、そして実行までの手順を紹介します。
ファイルの雛形の作成
ファイルの雛形の作成方法については初回でも紹介しましたが、以下に改めて作成するための方法を記述します。今回は”pzip”というモジュール名にしました。
$/usr/local/src/php-5.4.16/ext/ext_skel --extname=pzip --skel=/usr/local/src/php-5.4.16/ext/skeleton/
クラスファイルの作成
それぞれのクラス定義に相当するように、2つのファイルを作成します。
- pzip_file.c(PZipFileクラスを定義するCファイル)
- pzip_entry.c(PZipEntryクラスを定義するCファイル)
まずは、pzip_file.cの中身を以下に示します。
#ifdef HAVE_CONFIG_H #include "config.h" // : (省略) #include "php_pzip.h" zend_class_entry *pzip_file_ce; // ……(1) const zend_function_entry pzip_file_methods[] = { // ……(2) {NULL, NULL, NULL} }; PHP_MINIT_FUNCTION(pzip_file){ // ……(3) zend_class_entry ce; // ……(4) INIT_CLASS_ENTRY(ce,"PZipFile",pzip_file_methods); // ……(5) pzip_file_ce = zend_register_internal_class(&ce TSRMLS_CC); // ……(6) return SUCCESS; }
(1)のように1つのクラス定義につき、1つのzend_class_entry構造体を用意します。次に、(2)のように関数定義と同様にzend_function_entry構造体も用意します。クラス定義では、ここにメソッドを登録していきます。まだ、メソッド、プロパティもないクラスなので実体もないのですが、ここまでがクラス定義の実体の部分です。
続いて、(3)のPHP_MINIT_FUNCTIONマクロはクラス定義をモジュールに登録する際に実行される部分の記述です。このマクロで作成される関数を通じてモジュールへのクラス登録を行います。まず、一時的に(4)zend_class_entryの変数を用意し、そこに(5)INIT_CLASS_ENTRYマクロを利用しクラス名の設定と(2)で定義したメソッドを追加します。
そして、最後に(6)zend_register_internal_classを使って(1)で用意した変数へと設定する流れになります。
同様に、pzip_entry.cの内容も下記に示します。
zend_class_entry *pzip_entry_ce; const zend_function_entry pzip_entry_methods[] = { {NULL, NULL, NULL} }; PHP_MINIT_FUNCTION(pzip_entry){ zend_class_entry ce; INIT_CLASS_ENTRY(ce,"PZipEntry",pzip_entry_methods); pzip_entry_ce = zend_register_internal_class(&ce TSRMLS_CC); return SUCCESS; }
クラス名の設定や変数名以外はほぼ同様です。
メインプログラムへの登録
先ほどの2つのプログラムは、そのままの状態では実際にモジュールには登録されません。モジュールに登録するには、ext_skelコマンドで作成されたpzip.cファイル内にあるモジュールの初期化処理の部分で先ほどのPHP_MINIT_FUNCTIONマクロを使って作成した関数を実行します。
PHP_MINIT_FUNCTION(pzip) { // クラスごとに以下の行を記述する PHP_MINIT(pzip_file)(INIT_FUNC_ARGS_PASSTHRU); // ……(1) PHP_MINIT(pzip_entry)(INIT_FUNC_ARGS_PASSTHRU); // ……(2) return SUCCESS; }
(1)、(2)定義の時に作成したマクロはPHP_MINIT_FUNCTIONですが、実行時に使用するマクロはPHP_MINITになります。また、INIT_FUNC_ARGS_PASSTHRUはPHP_MINIT_FUNCTIONマクロで作成される関数の引数が設定されます。マクロばかりでよく内容が見えませんが、あまり深く考えずに決まりとして覚えてしまっても問題ありません。