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

第2回 Hello, PHP Extension!

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

今回から実際に拡張モジュールを作っていきます。まずは定番のHello, World!から始めましょう。

はじめてのspecファイル

CodeGen_PECLを使った拡張モジュールの開発には,まずXML形式で仕様を記述したspecファイルを書かねばなりません。リスト1に基本的なspecファイルの内容を示します。

リスト1 helloworld.xml

<?xml version="1.0" encoding="UTF-8"?>
<extension name="helloworld" version="1.0.0">
  <summary>Hello, Extension World!</summary>
  <description><?data
This is my first PHP extension module.
  ?></description>

  <maintainers>
    <maintainer>
      <user>rsk</user>
      <name>Ryusuke Sekiyama</name>
      <email>rsky0711@gmail.com</email>
      <role>lead</role>
    </maintainer>
  </maintainers>

  <license>PHP</license>

  <channel>__uri</channel>

  <release>
    <version>1.0.0</version>
    <date>2008-01-21</date>
    <state>stable</state>
    <notes><?data
- Initial release.
    ?></notes>
  </release>

  <function name="helloworld" role="public">
    <proto>void helloworld()</proto>
    <summary>Hello, World!</summary>
    <description><?data
Outputs "Hello, World!" and linebreak.
    ?></description>
    <code><?data
php_printf("Hello, World!%s", PHP_EOL);
    ?></code>
    <test>
      <code><?data
helloworld();
      ?></code>
      <result mode="plain"><?data
Hello, World!
      ?></result>
    </test>  
  </function>
</extension>

このようにspecファイルではXML宣言の後にルート要素として<extension>タグを配置し,その中にモジュール情報や関数定義を記述します。モジュール名は<extension>タグのname属性として記述します。また,<extension>タグにversion属性がないとpecl-genが警告を出すのですが,実際はversion属性は無視され,代わりに<release>タグの中の<version>タグの内容がモジュールのバージョン番号として扱われます。

モジュール情報

モジュールの説明は<extension>タグ直下の<summary>タグに概要を,<description>タグに詳細な内容を記述します。これら2つのタグは関数,クラス,メソッドなどの説明にも使われます。

加えて<maintainers>タグにモジュールのメンテナ,<license>タグにライセンス,<release>タグにバージョンなどの情報を記述します。バージョンが省略された場合は0.0.1develとみなされます。このほかに<changelog>タグの中に複数の<release>タグを書くことで更新履歴を表すこともできます。これらの情報はPEARパッケージを作るためのpackage.xmlにも反映されます。各タグの詳しい説明は付録Aをご覧ください。

関数定義

関数の定義は<function>タグで記述します。リスト1では1つだけしかありませんが,<extension>タグの中には複数の<function>タグを書くことができます。関数を提供しないモジュールなら<function>タグを省略しても構いません。

関数名は<function>タグのname属性で指定します。これは必須の属性です。role属性は省略可能で,デフォルト値はリスト1にあるのと同じくpublicです。role属性の値にはほかにinternalを指定してモジュール初期化時の処理などを記述できますが,本連載では,その手の処理が必要な場合は生成されたソースコードを直接編集します。

ここで,リスト1からhelloworld()関数を定義している部分を抜粋します。

リスト2 helloworld.xmlより関数定義部を抜粋

  <function name="helloworld" role="public">
    <proto>void helloworld()</proto>
    <summary>Hello, World!</summary>
    <description><?data
Outputs "Hello, World!" and linebreak.
    ?></description>
    <code><?data
php_printf("Hello, World!%s", PHP_EOL);
    ?></code>
    <test>
      <code><?data
helloworld();
      ?></code>
      <result mode="plain"><?data
Hello, World!
      ?></result>
    </test>  
  </function>

リスト2にあるように,関数の引数や戻り値に関する情報は<proto>タグに記述します。この情報を元にマニュアルやリフレクション情報,引数をパースするためのコードが生成されます。今回はただHello, World!を表示するだけの関数なので,戻り値はvoid,引数なしにしています。戻り値や引数の指定方法については次回に紹介します※1)。

関数の実装は<code>タグに記述します。今回はprintf(3)のZend API版であるphp_printf()関数でHello, World!を出力しています。PHP_EOLマクロはPHPのPHP_EOL定数と同じく改行コードを表す定数で,UNIX系ならLF("\n"),WindowsではCR+LF("\r\n")です※2)。

今回はspecファイルに関数の実装を書きましたが,関数が増えたり,その内容が複雑になってくるとspecファイルの見通しが悪くなりますし,C言語としてのキーワード補完などエディタのサポートも受けられません。そこで,次回からはspecファイルに書くのはプロトタイプまでに留め,実装はpecl-genで生成されたソースコード上に記述していきます。

<test>タグではmake testで実行されるテストケースを記述します。<code>タグの内容が実行されるPHPコード,<result>タグの内容が期待される出力です。出力結果の最初と最後のホワイトスペースは無視され,改行コードはLFに統一して評価されます。<test>タグを省略してもテストケースの雛形は生成されるので,後からテストケースを書いても(あるいは書かなくても)構いませんが,筆者は関数のプロトタイプと期待される結果はセットでspecファイルに書くほうが良いと考えます。

XML特殊文字について

ところでリスト1には内容が <?data ?> という処理命令で囲まれているタグがあります。これは内容をCDATA(構文解析されない文字データ)として扱うCodeGen_PECL独自の命令で,CDATAセクション(<![CDATA[ ]]>)と同じはたらきをします。構文解析されないということは <, >, &, " などの特殊文字をそのまま書けるということなので,特殊文字を含む内容は <?data ?> または <![CDATA[ ]]> で囲んでおくと見やすくなります。本連載では<description>や<code>などの内容が複数行にわたる可能性があるタグの内容は <?data ?>で囲み,インデントしないものとします。

※1

戻り値をvoidとし,<code>に戻り値に対する処理を書かなかった場合,関数はnullを返します。また,CodeGen_PECLではC言語のように引数をとらない関数の引数部を (void) としてはいけません。

※2

main/php.hで定義されています。Mac OS XではCR("\r")のように書かれていますが,CRはclassic Mac OSの改行コードで,Mac OS Xの改行コードはLFです。最近のMac OS Xのgccでは__MacOSX__マクロは定義されておらず,結果としてPHP_EOLはLFになります。ちなみにMac OS Xの判定には__APPLE__マクロが定義されているかを調べるのが一般的です。

著者プロフィール

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

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

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

コメント

コメントの記入