実例で学ぶPHP拡張モジュールの作り方

第3回 WEBカメラから画像をキャプチャ

この記事を読むのに必要な時間:およそ 9.5 分

ソースコードを生成する

これでspecファイルが用意できたので,pecl-genコマンドでモジュールのソースコードを生成します。今回は--dirオプションで出力先のディレクトリ名も指定しています。

操作1 pecl-genを実行

$ pecl-gen --dir=cvcapture-0.1.0 cvcapture-0.1.0.xml
Creating 'cvcapture' extension in './cvcapture-0.1.0'

Your extension has been created in directory ./cvcapture.
See ./cvcapture-0.1.0/README and/or ./cvcapture-0.1.0/INSTALL for further instructions.

ソースコード解説

前回は生成されたソースコードの説明を一切しなかったので,関数の実装に入る前に,生成されたファイルを少し眺めてみましょう。

バージョンチェック

まずはconfig.m4です。phpizeコマンドでは,このファイルの内容を元にconfigureスクリプトを生成します。中を見ると,pkg-configを使ってCPPFLAGSやLDFLAGSを設定したりしていますが,そこではなくAC_MSG_CHECKINGから始まる箇所に注目してください。ここでPHPのバージョンをチェックしています。cvcaptureモジュールではPHP 4互換のAPIしか使っていないので,PHPのバージョンが4.0.0以降かどうかを調べるコードが生成されました。

リスト5-1 PHPのバージョンチェック(config.m4)

  AC_MSG_CHECKING(PHP version)
  AC_TRY_COMPILE([#include <php_version.h>], [
#if PHP_VERSION_ID < 40000
#error  this extension requires at least PHP version 4.0.0
#endif
],
[AC_MSG_RESULT(ok)],
[AC_MSG_ERROR([need at least PHP 4.0.0])])

一見するとリスト5-1でちゃんとバージョンをチェックできているように思えますが,PHP_VERSION_IDはPHP 5.2以降でしか定義されていないマクロなので,PHP 4.4やPHP 5.1などでphpizeした場合,configureでエラーが出ます。本連載はPHP 5.2以降を対象にしていますが,それ以前のバージョンのPHPでも使えるようにしたいのなら,この箇所を丸ごと削除するか,リスト5-2のようにマクロPHP_MAJOR_VERSIONおよびPHP_MINOR_VERSIONを使ってバージョンを指定します。なお,これらのマクロはphp/main/php_version.hで定義されています。

リスト5-2 PHPのバージョンチェック(変更後)

  AC_MSG_CHECKING(PHP version)
  AC_TRY_COMPILE([#include <php_version.h>], [
#if PHP_MAJOR_VERSION < 4 || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION < 4)
#error  this extension requires at least PHP version 4.4.0
#endif
],
[AC_MSG_RESULT(ok)],
[AC_MSG_ERROR([need at least PHP 4.4.0])])

引数情報

次に,php_cvcapure.hを見てください。ここで注目すべきは関数の引数情報を定義するマクロZEND_BEGIN_ARG_INFO_EXです。これはPHP 5から実装されたリフレクションおよびタイプヒンティングのためのマクロで,ZEND_BEGIN_ARG_INFO_EX()からZEND_END_ARG_INFO()までの間にZEND_ARG_INFO()で個々の引数に関する情報(参照として受け取るか否かとリフレクション用の名前)を記述します。PHP 4向けにはNULLとなっていますが,もしcvcaptureモジュールをPHP 4.xでも使いたい場合は,ここを3番目の引数を参照として受け取ることを示す変数third_arg_force_refにしてください。

リスト6 引数情報定義(php_cvcapture.h)

PHP_FUNCTION(cv_file_capture); /* 関数のプロトタイプ宣言 */
#if (PHP_MAJOR_VERSION >= 5)
ZEND_BEGIN_ARG_INFO_EX(cv_camera_capture_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
  ZEND_ARG_INFO(0, filename)
  ZEND_ARG_INFO(0, index)
  ZEND_ARG_INFO(1, size)
ZEND_END_ARG_INFO()
#else /* PHP 4.x */
#define cv_camera_capture_arg_info NULL /* third_arg_force_refに変更する */
#endif

これらの情報はcvcapture.cにあるモジュールが提供する関数のリストで使われます。

リスト7 関数リスト(cvcapture.c)

/* {{{ cvcapture_functions[] */
function_entry cvcapture_functions[] = {
  PHP_FE(cv_camera_capture   , cv_camera_capture_arg_info)
  PHP_FE(cv_file_capture     , cv_file_capture_arg_info)
  { NULL, NULL, NULL } /* 必ずヌル終端する */
};
/* }}} */

モジュール情報

モジュールに関する情報もメインのソースコードであるcvcapture.cに記述されています。特に重要なのがzend_function_entry構造体で,ここにモジュール情報のすべてが集約されています。

リスト8 モジュール情報(cvcapture.c)

/* {{{ cvcapture_module_entry
 */
zend_module_entry cvcapture_module_entry = {
  STANDARD_MODULE_HEADER, /* おまじない */
  "cvcapture", /* モジュール名 */
  cvcapture_functions, /* 関数リスト */
  PHP_MINIT(cvcapture),     /* Replace with NULL if there is nothing to do at php startup   */ 
  PHP_MSHUTDOWN(cvcapture), /* Replace with NULL if there is nothing to do at php shutdown  */
  PHP_RINIT(cvcapture),     /* Replace with NULL if there is nothing to do at request start */
  PHP_RSHUTDOWN(cvcapture), /* Replace with NULL if there is nothing to do at request end   */
  PHP_MINFO(cvcapture),
  "0.1.0", /* バージョン文字列 */
  STANDARD_MODULE_PROPERTIES /* おまじない */
};
/* }}} */

このうちPHP_{MINIT,MSHUTDOWN,RINIT,RSHUTDOWN,MINFO}は,それぞれモジュール初期化,モジュール終了,リクエスト初期化,リクエスト終了,モジュール情報表示の際に呼ばれるコールバック関数で,PHP_MINFO以外は必要なければNULLにしても構いません。cvcaptureモジュールではPHP_MINITに対応するPHP_MINFO_FUNCTIONで定数を定義しています。PHP_MINFOに対応するPHP_MINFO_FUNCTIONは値を返しませんが,それ以外のコールバック関数は初期化/終了に成功したらSUCCESS(マクロで,実体は0⁠⁠,失敗したらFAILURE(同-1)を返します。

リスト9 モジュール初期化関数(cvcapture.c)

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(cvcapture)
{
  REGISTER_LONG_CONSTANT("CV_CAP_ANY", CV_CAP_ANY, CONST_PERSISTENT | CONST_CS);
  /* (省略) */
  REGISTER_LONG_CONSTANT("CV_CAP_QT", CV_CAP_QT, CONST_PERSISTENT | CONST_CS);

  /* add your stuff here */

  return SUCCESS;
}
/* }}} */

著者プロフィール

関山隆介(せきやまりゅうすけ)

ジンガジャパン株式会社に所属。PHP拡張モジュールを作った数なら(たぶん)日本一。PHP 5.3に対応したものはPEARチャンネルGitHubで公開中。

URLhttp://d.hatena.ne.jp/rsky/