SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

PHPエクステンションの作り方

PHPエクステンションでHelloWorld

PHPエクステンションの作り方 第1回


  • X ポスト
  • このエントリーをはてなブックマークに追加

ビルドする

 次にビルドを行います。まず、先ほど編集したconfig.m4をconfigureオプションとして有効になるようphpizeコマンドを利用します。

phpizeの実行方法
$ /usr/local/php-ext/bin/phpize

 これはダイナミックモジュールを作成する場合に使用するコマンドです。実行すると、そのエクステンションのためだけのconfigureスクリプトを作成することができます。次に実際にconfigureスクリプトのhelpを見て、helloworldエクステンションのオプションが作成されたか確認します。

オプションの有効化の確認方法
$ ./configure --help | grep helloworld
  --enable-helloworld           Enable helloworld support

 オプションが使えることを確認したら、PHPをインストールしたときと同じような手順でビルドしていきます。ただし、複数のPHPをインストールしている時には特に注意すべきことがあります。それは何処にインストールしてあるPHPを使ってPHPをコンパイルするかです。これに関しては、--with-php-configを使って指定できるので、今回のエクステンション作成用にインストールしたPHPを使うように指定します。

configureの実行方法
$ ./configure --enable-helloworld --enable-debug --with-php-config=/usr/local/php-ext/bin/php-config $ make

 --with-php-configを指定しない場合、筆者の環境では以下のようなエラーがmake時に表示されました。

環境間違いの時のエラーの内容
ext/helloworld/helloworld.c:43: error: 'PHP_FE_END' undeclared here (not in a function)

 これは必要なマクロ定義がないことによるエラーです。RPMで既に入っていたPHP 5.3.3のヘッダファイルには、そのような定義がないことによってエラーが発生しています。このような問題はエクステンション開発に慣れてくると間違いにすぐ気がつくものですが、不慣れなうちは対処が難しいものです。面倒ではありますが、--with-php-configを指定する癖を付けましょう。

 ビルドに成功すると、以下のファイルが作成されています。

ビルド成功時の生成ファイル
modules/helloworld.so

実行してみる

 では、実際に実行してみましょう。

実行方法
$ /usr/local/php-ext/bin/php -d extension=modules/helloworld.so -f helloworld.php

 まずは、-dオプションを使ってビルドしたエクステンションを指定します。これでmake installを実行しなくても、作成したエクステンションを指定した実行ができます。実行結果は下記のとおりです。

実行結果
Functions available in the test extension:
confirm_helloworld_compiled

Congratulations! You have successfully modified ext/helloworld/config.m4. Module helloworld is now compiled into PHP.

確認スクリプトの内容を見る

 実際にコードを見る前に、確認スクリプトが何をやっているのか確認してみます。

helloworld.phpの抜粋
// 省略
$module = 'helloworld';
$functions = get_extension_funcs($module);
echo "Functions available in the test extension:$br\n";
foreach($functions as $func) {
    echo $func."$br\n";
}
echo "$br\n";
$function = 'confirm_' . $module . '_compiled';
if (extension_loaded($module)) {
        $str = $function($module);
} else {
        $str = "Module $module is not compiled into PHP";
}
echo "$str\n";

 8行目から12行目では、helloworldエクステンション内で定義されている関数名一覧を取得しています。先ほどの実行結果では、該当の部分として以下のように出力されました。

実行結果
Functions available in the test extension:
confirm_helloworld_compiled

 つまりhelloworldエクステンションには、confirm_helloworld_compiled関数が定義されていることがわかります。次に、16行目ではその関数を実行しています。以下のコードを実行していることと同様の処理を行っています。

コードの別の記述方法
confirm_helloworld_compiled("helloworld");

 この処理の実行結果は以下のようになります。

実行結果
Congratulations! You have successfully modified ext/helloworld/config.m4. Module helloworld is now compiled into PHP.

 この内容を踏まえ、続いて作成されたhelloworld.cの中身を見ていきます。

C言語側のソースを見る

 helloworld.c側でconfirm_helloworld_compiledの記述がされている部分を探すと、22行目に以下のようなコードがあり、関数を定義している部分だと推測がつきます。

関数の定義(helloworld.cの抜粋)
const zend_function_entry helloworld_functions[] = {
    PHP_FE(confirm_helloworld_compiled, NULL)       /* For testing, remove later. */
    PHP_FE_END  /* Must be the last line in helloworld_functions[] */
};

 さらに探してみますと、以下のような定義が見つかり、関数の中身を定義している部分だと推測がつきます。

confirm_helloworld_compiled関数の実装(helloworld.cの抜粋)
PHP_FUNCTION(confirm_helloworld_compiled)
{
    // 省略
}

 この内容に沿って新たに関数を定義していけば、問題なさそうだと判断できるのではないでしょうか。ただしPHPに限らず、C言語でモジュール開発などを行うとマクロが多用されています。従ってC言語といえども、参考書に載っているようなC言語の記述方法とは異なりますが、ある程度、ルールとしきたりと割り切って開発を進めていく必要があります。

 どうしても中身を知りたい場合は、マクロを展開した後のコードも参照する必要があります。その場合は、以下のようにgccのマクロ展開オプションなどを使用し、実際のマクロ展開後のコードを眺めることはできます。

マクロ記述の展開方法の例
$ gcc -E -I /usr/local/php-ext/include/php/Zend/ -I /usr/local/php-ext/include/php/main/ helloworld.c 

 ただし、マクロの展開後は人が読むことを考慮したものではありません。まずは、マクロのまま理解するようにしてください。

エクステンションの全体の構造

 エクステンションの全体の構造を定義しているのが、zend_module_entry構造体です。この構造体にエクステンションの動作を定義しています。今回のサンプルでは以下のような定義がされています。

helloworld.cの抜粋
zend_module_entry helloworld_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    "helloworld",
    helloworld_functions,
    PHP_MINIT(helloworld),
    PHP_MSHUTDOWN(helloworld),
    PHP_RINIT(helloworld),      /* Replace with NULL if there's nothing to do at request start */
    PHP_RSHUTDOWN(helloworld),  /* Replace with NULL if there's nothing to do at request end */
    PHP_MINFO(helloworld),
#if ZEND_MODULE_API_NO >= 20010901
    "0.1", /* Replace with version number for your extension */
#endif
    STANDARD_MODULE_PROPERTIES
};

 この構造体の関係と、実際にコード内で定義する場所を図に示します。

定義の構造体
定義の構造体

 このzend_module_entry構造体の定義はそのままに、当てはまる部分にコードを追記していけば、簡単なエクステンションは作成できるようになっています。

最後に

 今回はPHPエクステンションを作成しビルドから実行までの流れを確認し、そしてそのソースを通じて構造と関数の定義するための手順を紹介しました。ここまでの内容を参考に、自分が興味があるエクステンションのコードを読むことで、より一層の理解が深まると思います。次回は、今回紹介できなかった様々なパラメータの取得方法や戻り値の作成方法などを通じて、より本格的な関数の作成方法を紹介します。

参考資料

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
PHPエクステンションの作り方連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7246 2013/08/27 18:34

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング