ext_skelを使用してPHP拡張機能を実装します
1.前に書く
この記事はPHP7.4
、PHP拡張機能を最初から作成する方法に基づいています。この記事では、主に拡張機能を作成するための基本的な手順について説明します。この例では、次の関数を実装します。
<?phpecho hello();?> 12345
出力内容:
$ php74 ./hello.php $ hello word123
hello
メソッドを呼び出したhello
後、拡張機能にメソッドを実装します hello word!
。
2つ目は、コードを生成する
PHPには、基本的なコードを生成するためのツールext_skel.phpが用意されています。このツールは、PHPのソースコードphp-对应版本/ext/
ディレクトリにあります。
コマンドを入力 php ext_skel.php --ext_skel.php --ext hello --author sunct --std
すると、次のような効果があります。
$ php ext_skel.php ext_skel.php --ext hello --author sunct--std構成 スクリプトの コピー...完了ソースのコピー...完了 テストのコピー...完了 成功。これで、拡張機能をコンパイルする準備が整いました。そのためには、使用して 次のステップを: CD /パス/に/ PHP-srcが/ハロー は、phpize ./configureを 作り 、コンパイルが完了するとDOはテストを実行することを忘れないで: メイクテストは !PHPを使用していただきありがとうございます12345678910111213141516171819を
パラメータ--ext
を追加せずに直接実行するphp ext_skel.php
とError
、エラーが報告されます。
$ php ext_skel.php エラー:拡張子名が渡されていません。「-ext <name>」を使用してください1234
ext
ディレクトリには、下に生成される hello
ディレクトリ。
[外部リンク画像の転送に失敗しました。元のサイトにホットリンク防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします
。PHP拡張機能は、すべての拡張機能に共通の複数のファイルで構成されています。これらのファイルの詳細の多くは、異なる拡張子間で類似していますが、各ファイルの内容をコピーするのに手間がかかります。幸い、PHP 4.0以降に配布されている、ext_skelという名前のすべての初期化作業を実行できるスクリプトがあります。
以下は、ソースパッケージ内のjson
ファイルの内容です。
オプションのパラメータ:
オプション phpext_skel.php --ext <name> [--experimental] [--author <name>] [--dir <path>] [--std] [--onlyunix] [--onlywindows] [- help] --ext <name> <name>として定義された拡張機能の名前// <name>として定義された拡張機能 --experimentalこの拡張機能が実験的な場合に渡さ れ、拡張機能のルートにEXPERIMENTALファイルが作成され ます//この拡張子が実験的なものである場合は、拡張子のルートディレクトリにあるEXPERIMENTALファイルを使用します --author <name>あなたの名前。これは--stdが渡された場合に使用され、 CREDITSファイルの場合は//あなたの名前(渡された場合)-std、 CREDITSファイルは、この名前を使用しますこのスクリプトは、どこのディレクトリにデフォルト 住んでいます --dir <path>拡張子が必要なディレクトリへのパス 作成した。デフォルトは、このスクリプトが配置されているディレクトリです --std渡さ れると、コアに含まれる拡張機能で使用される標準ヘッダーが使用され ます --onlyunixUnixの構成スクリプトのみを生成します--onlywindowsWindowsの構成スクリプトのみを生成します --helpこのヘルプ12345678910111213141516171819
一般的に、新しい拡張機能を開発する場合、関係するパラメーターは --ext name
合計のみ --help
です。拡張機能の構造に既に精通している場合を除き、このパラメーターを指定すると、ext_skelは生成されたファイル内の多くの有用なコメントを省略しません。
残りの--ext名は、拡張子の名前を渡し ext_skel
ます。「名前」は1つで全为小写字母的标识符
、含まれているだけ で、字母和下划线
PHP配布パッケージのext/
フォルダーにあります 唯一
。
3、config.m4構成ファイルを変更します
拡張config.m4ファイルは、サポートされている拡張構成オプション、必要な拡張ライブラリ、およびその一部としてコンパイルするソースファイルをUNIXビルドシステムに通知します。PHP固有のautoconf組み込みマクロを含む、頻繁に使用されるすべてのautoconfマクロ用。
config.m4の役割は、phpizeツールを使用して構成ファイルを生成することです。構成ファイルは、環境の検出に使用されます。拡張機能のコンパイルと実行に必要な環境が満たされているかどうかを確認してください。ここで、config.m4ファイルの変更を開始します。
その中で、dnlはコメント記号です。
上記のコードは、作成する拡張機能が他の拡張機能またはlibライブラリに依存している場合、PHP_ARG_WITH
関連するコードのコメントを解除する必要があることを示しています。それ以外の場合は、PHP_ARG_ENABLE
関連するコードセグメントのコメントを解除し ます。私たちが書く拡張機能は、他の拡張機能やlibライブラリに依存する必要はありません。したがって、PHP_ARG_ENABLE
前のコメントを削除します。
上記の図が生成されたとき、他の拡張子に依存しないことが指定されています。
4、コードの実装
hello.cファイルを変更します。helloメソッドを実装します。
実行中 php ext_skel.php --ext hello
に、hello.c
ファイルは2つのテストメソッドを生成しました:hello_test1
とhello_test2
。
ファイル生成コード:
/ * { { {void hello_test1() * / PHP_FUNCTION(hello_test1){ ZEND_PARSE_PARAMETERS_NONE(); php_printf( "拡張子%sが読み込まれ、機能しています!\ r \ n"、 "hello");} / *}}} * // * { { {string hello_test2([string $ var]) * / PHP_FUNCTION(hello_test2 ){ char * var = "World"; size_t var_len = sizeof( "World")-1; zend_string * retval; ZEND_PARSE_PARAMETERS_START(0、1) Z_PARAM_OPTIONAL Z_PARAM_STRING(var、var_len) ZEND_PARSE_PARAMETERS_END(); retval = strpprintf(0、 "Hello%s"、var); RETURN_STR(retval);} 123456789101112131415161718192021222324252627
その中で:
関数
hello_test1()
出力の実行は、The extension hello is loaded and working!
パラメーターを渡すことができないかecho hello_test1('这是一个参数');
、エラーを報告できません警告:PHP Warning: hello_test1() expects exactly 0 parameters, 1 given in /Users/sunct/code/php/hello.php on line 2
;
実行関数
hello_test2()
はを出力Hello World
し、関数はパラメータを渡すことができますhello_test2('这是一个参数')
、出力:Hello 这是一个参数
hello
関数をモデル化して、関数の後に置くことができ ますPHP_FUNCTION(hello_test2)
。
/ *新しい関数* / PHP_FUNCTION(hello){ zend_string * strg; strg = strpprintf(0、 "hello word"); RETURN_STR(strg);} 12345678
出力に使用 hello word
PHP_FE_ENDを見つけて、上記のコードを追加します。
PHP_FE(hello、NULL)1
写真が示すように:
5、コンパイルしてインストール
cd hello / phpize ./configure make1234
それらの中で:./configure
あなた自身の環境に従ってパラメータを追加してください。
私が使用するテストを容易にするために:./configure --prefix=/usr/local/php7 --without-iconv --with-apxs2 --enable-fpm --with-config-file-path=/usr/local/php7/etc;
php.iniファイルを変更し、次のコードを追加します。
拡張= say.so1
実施した:
php -m1
表示されない場合hello
、現在のPHPを使用すると、次の警告エラーが表示されます。
PHP警告:PHPスタートアップ:ダイナミックライブラリ 'hello.so'を読み込めません(試行:/usr/local/php7/lib/php/extensions/no-debug-non-zts-20190902/hello.so(dlopen(/ usr /local/php7/lib/php/extensions/no-debug-non-zts-20190902/hello.so、9):画像が見つかりません)、/ usr / local / php7 / lib / php / extensions / no-debug- non-zts-20190902 / hello.so.so(dlopen(/usr/local/php7/lib/php/extensions/no-debug-non-zts-20190902/hello.so.so、9):画像が見つかりません) )行01の不明
これは、/usr/local/php7/lib/php/extensions/no-debug-non-zts-20190902/hello.so
ファイルが存在しないことを示していますhello.so
。生成されたファイルをここに手動で移動できます。
コンパイルと実行を開始すると、hello
生成されたmodules
フォルダーの下にフォルダーが生成されます。hello.so
ファイルに移動:
sudo cp〜 / code / php / php-7.4.13 / ext / hello / modules / hello.so /usr/local/php7/lib/php/extensions/no-debug-non-zts-20190902/hello.so1
phpinfo()を表示:
6、テストを呼び出す
PHPファイルを作成し、helloメソッドを呼び出します。出力コンテンツが期待を満たしているかどうかを確認します。
結果は次のとおりです。
<?php echo "\ r \ n実行hello()----:"。hello(); echo "\ r \ n実行hello_test2()----:"。hello_test2(); echo "\ r \ nExecutehello_test2 ( 'これはパラメータです')----: "。hello_test2( 'これはパラメータです'); echo" \ r \ n実行hello_test1()----: "。hello_test1(); 12345
セブン、※ファイルを分析する
1、config.m4
UNIXビルドシステム構成
2、config.w32
Windowsビルドシステム構成
3、php_hello.h
拡張機能を静的モジュールとしてPHPバイナリファイルにビルドする場合、ビルドシステムは、拡張モジュール構造へのポインターの宣言を含む拡張機能名の前に、php_がヘッダーファイルを追加することを期待します。他のヘッダーと同様に、このファイルには通常、他のマクロ、プロトタイプ、およびグローバル変数が含まれています。
4、hello.c
メインの拡張ソースファイル。慣例により、ファイル名は拡張子ですが、これは必須ではありません。このファイルには、モジュール構造宣言、INIエントリ、管理機能、ユーザースペース機能、およびその他の拡張機能の要件が含まれています。
PHP拡張機能のメインソースファイルには、Cプログラムの構造が含まれています。これらの中で最も重要なのはzend_module構造体です。これは、新しい拡張機能を作成するときの最初の連絡先です。この構造には、Zend Engine拡張機能の依存関係、バージョン、コールバック、その他の重要なデータを伝える多くの情報が含まれています。
/ * { { {hello_module_entry * / zend_module_entry hello_module_entry = { STANDARD_MODULE_HEADER、 "hello"、/ *拡張子名* / hello_functions、/ * zend_function_entry * / NULL、/ * PHP_MINIT-モジュールの初期化* / NULL、/ * PHP_MSHUTDOWN-モジュールのシャットダウン* / PHP_RINIT(hello)、/ * PHP_RINIT-初期化要求* / NULL、/ * PHP_RSHUTDOWN-シャットダウン要求* / PHP_MINFO(hello)、/ * PHP_MINFO-モジュール情報* / PHP_HELLO_VERSION、/ *バージョン* / STANDARD_MODULE_PROPERTIES}; / *} }} * / 123456789101112131415
モジュール構造フィールド値
フィールド | 値 | 説明 |
---|---|---|
サイズ[^ 1] [^ 1] [^ 2] [^ 3] | sizeof(zend_module_entry) | 構造体のバイトサイズ。 |
zend_api [^ 1] [^ 2] [^ 3] | ZEND_MODULE_API_NO | このモジュールの対象となるZendAPIバージョン。 |
zend_debug [^ 1] [^ 2] [^ 3] | ZEND_DEBUG | モジュールがデバッグをオンにしてコンパイルされているかどうかを示すフラグ。 |
zts [^ 1] [^ 2] [^ 3] | USING_ZTS | モジュールがZTS(TSRM)を有効にしてコンパイルされているかどうかを示すフラグ(メモリ管理を参照)。 |
ini_entry [^ 1] [^ 3] | ヌル | Zendはこのポインタを内部的に使用して、モジュールによって宣言されたINIエントリへの非ローカル参照を維持します。 |
deps [^ 3] | ヌル | モジュールの依存関係のリストへのポインター。 |
名前 | 「mymodule」 | モジュールの名前。これは、「spl」や「standard」などの略語です。 |
関数 | mymodule_functions | モジュール関数テーブルへのポインターであるZendは、このポインターを使用して、モジュール内の関数をユーザースペースに公開します。 |
module_startup_func | PHP_MINIT(mymodule) | モジュールが最初にPHPの特定のインスタンスにロードされたときにZendが呼び出すコールバック関数。 |
module_shutdown_func | PHP_MSHUTDOWN(mymodule) | 通常、最終シャットダウン中のコールバック関数であるZendは、モジュールが特定のPHPインスタンスからアンロードされたときにこの関数を呼び出します。 |
request_startup_func | PHP_RINIT(mymodule) | Zendは、各リクエストの開始時にコールバック関数を呼び出します。この関数を呼び出すとすべてのリクエストにコストがかかるため、この関数はできるだけ短くするか、空にする必要があります。 |
request_shutdown_func | PHP_RSHUTDOWN(mymodule) | Zendが各リクエストの最後に呼び出すコールバック関数。この関数を呼び出すとすべてのリクエストにコストがかかるため、この関数はできるだけ短くするか、空にする必要があります。 |
info_func | PHP_MINFO(mymodule) | `phpinfo()`関数が呼び出されたときにZendが呼び出すコールバック関数。 |
バージョン | NO_VERSION_YET | モジュール開発者によって指定された、モジュールバージョンを示す文字列。バージョン番号は、 `version_compare()`で期待される形式(たとえば、「1.0.5-dev」)またはCVSまたはSVNリビジョン番号(たとえば、「$ Rev:322138 $」)を採用することをお勧めします。 |
globals_size [^ 1] [^ 4] [^ 5] [^ 6] | sizeof(zend_mymodule_globals) | モジュールのグローバル変数を含むデータ構造のサイズ(存在する場合)。 |
globals_id_ptr [^ 1] [^ 4] [^ 5] [^ 6] [^ 7] | &mymodule_globals_id | USING_ZTS定数が真であるかどうかに応じて、これら2つのフィールドの1つだけが存在します。前者はTSRM割り当てテーブル内のモジュールのグローバル変数のインデックスであり、後者はグローバル変数への直接のポインタです。 |
globals_ptr [^ 1] [^ 4] [^ 5] [^ 6] [^ 8] | &mymodule_globals_id | |
globals_ctor [^ 4] [^ 5] [^ 6] | PHP_GINIT(mymodule) | この関数は、 `module_startup_func`の前にモジュールのグローバル変数を初期化するために呼び出されます。 |
globals_dtor [^ 4] [^ 5] [^ 6] | PHP_GSHUTDOWN(mymodule) | この関数は、 `module_shutdown_func`の後にモジュールのグローバル変数を解放するために呼び出されます。 |
post_deactivate_func [^ 4] | ZEND_MODULE_POST_ZEND_DEACTIVATE_N(mymodule) | この関数は、リクエストが閉じられた後にZendによって呼び出されます。めったに使用されません。 |
module_started [^ 1] [^ 9] [^ 4] | 0 | これらのフィールドは、Zendの内部追跡情報に使用されます。 |
タイプ[^ 1] [^ 9] [^ 4] | 0 | |
ハンドル[^ 1] [^ 9] [^ 4] | ヌル | |
module_number [^ 1] [^ 9] [^ 4] | 0 |
[^ 1]このフィールドはモジュール開発者には適用されません。
[^ 2]このフィールドはSTANDARD_MODULE_HEADER_EX
。で埋められます。
[^ 3]このフィールドはSTANDARD_MODULE_HEADER
。で埋められます。
[^ 4]このフィールドはSTANDARD_MODULE_PROPERTIES
。で埋められます。
[^ 5]このフィールドはNO_MODULE_GLOBALS
。で埋められます。
[^ 6]このフィールドはPHP_MODULE_GLOBALS
。で埋められます。
[^ 7] USING_ZTSがtrueの場合のみ、このフィールドはtrueです。
[^ 8] USING_ZTSがの場合のみ、このフィールドはfalseになります。
[^ 9]このフィールドはSTANDARD_MODULE_PROPERTIES_EX
。で埋められます。