この記事では、PHP 拡張機能開発の入門チュートリアルを中心に、C 言語を使用して Linux システムで PHP 拡張機能を開発するために必要な最も基本的な知識を説明します。参考になります
PHP拡張機能の開発
私は、この一連のブログ投稿で PHP 拡張機能の開発について学んだことと洞察を要約し、Linux システムで PHP 拡張機能を開発するために知っておくべき最も基本的な知識を簡単かつ明確に説明するつもりです。レベルが低いので間違いがあるかもしれませんがご指摘ください。
準備
まず、PHP ソース コードのコピーを取得し (Github からチェックアウトするか、公式 Web サイトから最新の安定バージョンをダウンロードできます)、コンパイルします。コンパイルを高速化するには、余分な拡張機能をすべて無効にすること (--disable-all オプションを使用) をお勧めしますが、デバッグ (--enable-debug オプションを使用) とスレッド セーフ (--enable-maintainer を使用) をオンにすることをお勧めします。 -zts)、ただし、拡張機能を公開するときにデバッグをオフにし、状況に応じてスレッド セーフをオンにするかどうかを選択する必要があります:
コードは次のとおりです:
コンパイルされた PHP 実行可能プログラムは、ソース コードの sapi ディレクトリにあります。将来的には、主に cli (コマンド ライン インターフェイス) 環境を使用することになります。 :
コードは次のとおりです:
便利なコマンドライン オプションがいくつかあります:
コードは次のとおりです:
#コード内でコードを実行します
拡張スケルトン
PHP のすべての公式拡張機能はソース コードの ext ディレクトリにあり、自分で作成した拡張機能もこのディレクトリに配置できます。このディレクトリには、PHP 拡張機能のスケルトンを生成するために使用される ext_skel という名前のシェル スクリプトがあることに注意してください。このスクリプトを使用すると、PHP 拡張機能をすばやく作成できます。
コードは次のとおりです:
$ ./ext_skel --extname=myext
上記のコマンドは、myext という名前の拡張機能を作成するのに役立ちます。ソース コードは myext ディレクトリにあります。パラメーターを指定せずにスクリプトを実行すると、ヘルプ情報が出力され、スクリプトによって提供されるその他のオプションを確認できます。
次に拡張機能を完成させましょう。 myext ディレクトリに入り、config.m4 構成ファイルを編集し、PHP_ARG_ENABLE マクロ関数を見つけて、前の dnl コメント (合計 3 行) を削除します。ソース コードのルート ディレクトリに戻り、buildconf、configure、make コマンドを再実行します。
コードは次のとおりです:
$ ./buildconf --force
$ ./configure --help grep myext |
--enable-myext myext サポートを有効にする
$ ./configure --disable-all --enable-myext --enable-debug --enable-maintainer-zts
$メイク
拡張機能の読み込みステータスを出力するために ./configure --help | grep myext を使用したことに注意してください。以下の出力が表示されない場合は、戻って config.m4 ファイルを確認してください。 。
コードの大部分はすでにコンパイルされているため、このコンパイルは非常に高速になるはずです。 PHP には拡張機能をコンパイルする別の方法 (拡張機能を .so ファイルにコンパイルする動的リンクを使用する) がありますが、拡張機能を開発する場合は静的コンパイルを使用することをお勧めします。これにより、構成ファイルに拡張機能をロードする必要がなくなるためです。
すべてがうまくいけば、最初の拡張機能を実行する準備が整います:
コードは次のとおりです:
$ php-dev -m grep myext
私の次
$ php-dev -r 'echoconfirm_myext_compiled("myext") "n";'
おめでとうございます! ext/myext/config.m4 が正常に変更されました。モジュール myext が PHP にコンパイルされました。
最初のコマンドは、拡張機能がロードされたことを示しています。 2 番目のコマンドは、ext_skel 拡張スケルトンが自動的に作成した関数を実行します。もちろん、この関数には意味はありませんが、この関数を hello world に簡単に適用できます。
拡張機能を手動で作成する
ほとんどのチュートリアルでは、ext_skel 拡張スケルトンをプロトタイプとして使用して、拡張機能の開発を説明します。もちろん、このアプローチは非常に便利で高速です。しかし、私は個人的には拡張機能を純粋に手作業で開発することを好みます。なぜなら、あらゆる詳細を理解するのが簡単だからです。
拡張機能を手動で作成するには、まず ext ディレクトリに入り、拡張機能ディレクトリ myext2 を作成します。いくつかのファイルが必要です: config.m4、myext2.c、php_myext2.h。
まず、構成ファイル config.m4 を書きましょう:
コードは次のとおりです:
PHP_ARG_ENABLE(myext2, myext2 サポートを有効にするかどうか,
[ --enable-myext2 myext2 サポートを有効にする])
if テスト "PHP_MYEXT2" != "no" then
PHP_NEW_EXTENSION(myext2, myext2.c, $ext_shared)
ふぃ
config.m4 は、実際には autoconf プログラムによって使用される構成ファイルです。Autoconf は autotools ツールボックスの重要なコンポーネントです。 autoconf の使用法を完全に紹介するには長い時間がかかりますが、幸いなことに、ここでの使用法は非常に簡単です。
PHP_ARG_ENABLE は、autoconf 用に PHP によって定義されたマクロ関数です。myext2 はその最初のパラメーターで、拡張機能の名前を示します。最後の 2 つのパラメーターは、make と configure が実行されるときの表示にのみ使用されるため、必要なものを自由に記述できます。 [ ] は、autoconf 構文の二重引用符のように機能し、文字列をラップするために使用されます (2 番目のパラメーターにはスペースが含まれていますが、角括弧で囲む必要はないことに注意してください)。拡張機能がデフォルトでオンであるかオフであるかを示すために使用される 4 番目のパラメーターもあります (デフォルトは no)。
次の 3 行は、実際には PHP_MYEXT2 拡張モジュールが有効になっているかどうかを判断するためのシェル構文です。拡張モジュールが有効になっている場合 (--enable-myext2)、$PHP_MYEXT2 変数の値は no ではないため、PHP_NEW_EXTENSION マクロが実行されます。このマクロ関数は、autoconf 用に PHP によって定義された拡張構文でもあります。最初のパラメーターは拡張機能の名前でもあり、2 番目のパラメーターは拡張機能によってコンパイルされる C ファイルです。複数ある場合は、それらを順番に書き留めます。スペースで区切ります); 3 つのパラメータは $ext_shared に固定されます。
次に、php_myext2.h ヘッダー ファイルを作成します。このファイルの名前は、PHP 拡張機能の仕様である php_extension.h です。
コードは次のとおりです:
#ifndef PHP_MYEXT2_H
#define PHP_MYEXT2_H
extern zend_module_entry myext2_module_entry;
#define phpext_myext2_ptr &myext2_module_entry
#define PHP_MYEXT2_VERSION "0.1.0"
/* プロトタイプ */
PHP_FUNCTION(こんにちは);
#endif /* PHP_MYEXT2_H */
ここでのメインコードは、phpext_myext2_ptr という名前のマクロを定義することです。PHP の最下層は、このマクロを通じて拡張機能を参照します。このマクロの名前も標準化されていることがわかります - phpext_extension_ptr。 Myext2_module_entry は、後で .c ファイル内で定義する構造体であり、その名前も標準化されています (extension _module_entry)。
さらに、拡張バージョン番号と関数プロトタイプを識別するマクロも定義しました (PHP_FUNCTION マクロを通じて、PHP_FUNCTION マクロ関数のパラメーターは、後でこの関数を実装します)。
最後に、myext2.c ファイルの実装を見てみましょう:
コードは次のとおりです:
#include "php.h"
#include "php_myext2.h"
/* {{{ myext2_functions[]
*
* ユーザーに表示されるすべての関数は、myext2_functions[] にエントリが必要です。
*/
static const zend_function_entry myext2_functions[] = {
PHP_FE(こんにちは、NULL)
PHP_FE_END
};
/* }}} */
/* {{{ myext2_module_entry
*/
zend_module_entry myext2_module_entry = {
STANDARD_MODULE_HEADER、
"myext2", /* モジュール名 */
myext2_functions, /* モジュール関数 */
NULL, /* モジュールを初期化します */
NULL, /* モジュールのシャットダウン */
NULL, /* 初期化リクエスト */
NULL, /* シャットダウンを要求 */
NULL, /* phpinfo */
PHP_MYEXT2_VERSION, /* モジュールのバージョン */
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_MYEXT2
ZEND_GET_MODULE(myext2)
#endif
/* {{{ proto void hello()
「ハローワールド!」を印刷します */
PHP_FUNCTION(こんにちは)
{
php_printf("hello world!n");
}
/* }}} */
拡張機能スケルトンによって作成された .c ファイルを比較すると、実際、最も基本的な拡張機能にはこれらで十分であることがわかります。
上記のコードはシンプルかつ明確で、コメントのほとんどはすでに非常に説明的です。簡単にまとめてみましょう:
1. 先頭には使用するヘッダー ファイルが含まれています。 php.h は必要です。これは、stdio.h、stdlib.h など、使用する標準ライブラリ ファイルのほとんどをインクルードするのに役立ちます。
2.myext2_functions は、公開する関数で構成される構造体配列を定義します。各要素は PHP_FE マクロを通じて指定されます。 PHP_FE マクロには 2 つのパラメータがあります。1 つ目は外部で使用できる関数名、2 つ目はパラメータ情報 (ここでは単に NULL を使用します)、最後の要素は PHP_FE_END である必要があります。ここでも、そのコメントに注意してください。外部に公開されるすべての関数は、構造体配列で定義する必要があります。
3.myext2_module_entry はモジュール情報を定義します。これは構造体であり、ほとんどの属性はコメントで説明されています。中央の 5 つの関数ポインターに注目してください。これらの関数ポインターは単に NULL に設定されています。その使用方法については、後続のブログ投稿で説明します。
4. ZEND_GET_MODULE (myext2) マクロ関数は ifdef マクロに組み込まれているため、呼び出されるかどうかは状況によって異なります。呼び出される状況と呼び出されない状況については、今後のブログ投稿で説明します。
5. コードの最後の数行では、php_printf を呼び出して改行文字を出力します。php_printf の使用法は printf とまったく同じです。
6. コメント内の {{{ と }}} は、vim などのエディターでの折りたたみを容易にするために使用されます。この方法でコメントを記述することをお勧めします。
これには、PHP_FE、PHP_FE_END、PHP_FUNCTION などのいくつかのマクロが含まれます。これらのマクロの詳細については、後続のブログ投稿で説明します。現時点での最も簡単な方法は、これらのマクロを覚えておくことです。
各ファイルの名前、変数、スペース、インデント、コメントの名前が非常に標準化されていることに注意してください。これらの仕様に従うと、作成するコードが PHP 自体のコードとより一貫性を持つようになります。 PHP 拡張機能を開発するための仕様。
最後に、拡張機能をコンパイルして実行します:
コードは次のとおりです:
$ ./buildconf --force
$ ./configure --help grep myext2
--enable-myext2 myext2 サポートを有効にする
$ ./configure --disable-all --enable-myext2 --enable-debug --enable-maintainer-zts
$make
$ php-dev -m
myext2
$ php-dev -r 'hello();'
ハローワールド!