ホームページ > バックエンド開発 > PHPチュートリアル > PHP拡張用拡張フレームワークの自動生成

PHP拡張用拡張フレームワークの自動生成

黄舟
リリース: 2023-03-15 07:20:01
オリジナル
2048 人が閲覧しました

まえがき

前回の記事: 初心者がPHP拡張機能を学ぶ - hello world 理由はともかく、PHP拡張機能に強制的に挨拶する。 ext_skelで自動生成されるフレームワークについては、メモも兼ねてこの記事で詳しく解説します。

テキスト

ext_skel

./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]
           [--skel=dir] [--full-xml] [--no-help]

  --extname=module   module is the name of your extension(模块名,会在当前目录创建一个该名称子目录)
  --proto=file       file contains prototypes of functions to create(函数原型定义文件)
  --stubs=file       generate only function stubs in file
  --xml              generate xml documentation to be added to phpdoc-cvs
  --skel=dir         path to the skeleton directory(设置骨架生成的目录,不设置该项则默认在ext/extname下)
  --full-xml         generate xml documentation for a self-contained extension
                     (not yet implemented)
  --no-help          don't try to be nice and create comments in the code                     
  and helper functions to test if the module compiled (生成的代码中不显示各种帮助注释)
ログイン後にコピー

PHP と拡張機能関連のプロセスの使用法

1. 概念的には、PHP プログラムの起動と終了は 2 つに分かれています。

1 つは、php モジュールがロードされるときに、モジュール起動関数がエンジン (PHP_MINIT_FUNCTION) によって呼び出されることです。これにより、エンジンはリソース タイプや INI 変数の登録などの初期化を行うことができ、これらのデータは終了 (PHP_MSHUTDOWN_FUNCTION) に対応してメモリ内に常駐します

もう 1 つは、PHP リクエストの開始時、スタートアップ関数の前です。リクエスト (PHP_RINIT_FUNCTION) を呼び出すだけです。これはリクエスト完了後の終了に相当します (PHP_RSHUTDOWN_FUNCTION)

2. PHP が起動すると、ロードされたすべての拡張機能の MINIT メソッド (正式名: Module Initialization) の処理が開始されます。 )(PHP_MINIT_FUNCTION) は、この間に 1 回実行され、拡張機能はユーザー側の PHP スクリプトで使用される独自の定数、クラス、リソースなどの一部を定義できます。 ここで定義されたものはメモリ内に常駐し、PHP モジュールがオフになるまですべてのリクエストで使用できます。

3. リクエストが届くと、PHP はすぐに新しい環境を開き、独自の拡張機能を再スキャンし、それぞれの RINIT メソッド (フルネーム リクエストの初期化) (PHP_RINIT_FUNCTION) を走査して実行します。このとき、拡張機能が初期化される場合があります。このリクエストで使用される変数などは、後でクライアント (つまり、PHP スクリプト) の変数などでも初期化されます。

4. リクエストがビジネスコードを通過して最後まで実行されると、PHP はリサイクルプログラムを開始し、実行が完了すると、変数テーブル内のすべての変数、このリクエストで適用されたすべてのメモリなど、このリクエストで使用されたすべてが解放されます。

5.完了すると、クローズする時間になり、PHP は MSHUTDOWN (フルネーム モジュール シャットダウン) (PHP_MSHUTDOWN_FUNCTION) ステージに入ります。この時点で、まだ満たされていない拡張機能がある場合は、PHP がすべての拡張機能に最後通告を発行します。独自の MSHUTDOWN メソッドでは、これが最後のチャンスです。PHP が拡張 MSHUTDOWN の実行を完了すると、自己破壊プログラムに入ります。 (許可なく申請されたメモリをクリアする最後のチャンスです。そうでないとメモリがリークします)

私が理解した概要、プロセス:
PHP_MINIT_FUNCTION (プロセスごとに 1 回実行)
|
多くの PHP_RINIT_FUNCTION を実行します
|
多くの PHP_RSHUTDOWN_FUNCTION を実行します
|
PHP_MSHUTDOWN_FUNCTION (プロセスごとに1回実行)

マルチスレッドとマルチプロセスの図を添付します
PHP拡張用拡張フレームワークの自動生成

PHP拡張用拡張フレームワークの自動生成

config.m4

dnlは、phpの//と同じで、この行をコメントアウトすることを意味します。なぜDNLなのかは勉強しません、ただメモであることだけ知っておいてください。

dnl $Id$
dnl config.m4 for extension helloworld

dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:##指定PHP模块的工作方式,动态编译选项,如果想通过.so的方式接入扩展,请去掉前面的dnl注释PHP_ARG_WITH(helloworld, for helloworld support,
Make sure that the comment is aligned:
[  --with-helloworld             Include helloworld support])

dnl Otherwise use enable:##指定PHP模块的工作方式,静态编译选项,如果想通过enable的方式来启用,去掉dnl注释PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
Make sure that the comment is aligned:
[  --enable-helloworld           Enable helloworld support])if test "$PHP_HELLOWORLD" != "no"; then
  dnl Write more examples of tests here...

  dnl # --with-helloworld -> check with-path
  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this
  dnl SEARCH_FOR="/include/helloworld.h"  # you most likely want to change this
  dnl if test -r $PHP_HELLOWORLD/$SEARCH_FOR; then # path given as parameter
  dnl   HELLOWORLD_DIR=$PHP_HELLOWORLD
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for helloworld files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       HELLOWORLD_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl 
  dnl if test -z "$HELLOWORLD_DIR"; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the helloworld distribution])
  dnl fi

  dnl # --with-helloworld -> add include path
  dnl PHP_ADD_INCLUDE($HELLOWORLD_DIR/include)
  dnl # --with-helloworld -> check for lib and symbol presence
  dnl LIBNAME=helloworld # you may want to change this
  dnl LIBSYMBOL=helloworld # you most likely want to change this 

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $HELLOWORLD_DIR/$PHP_LIBDIR, HELLOWORLD_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_HELLOWORLDLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong helloworld lib version or lib not found])
  dnl ],[
  dnl   -L$HELLOWORLD_DIR/$PHP_LIBDIR -lm
  dnl ])
  dnl  ##用于说明这个扩展编译成动态链接库的形式
  dnl PHP_SUBST(HELLOWORLD_SHARED_LIBADD)  ##用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开
  PHP_NEW_EXTENSION(helloworld, helloworld.c, $ext_shared)fi
ログイン後にコピー

php_helloworld.h

インターネット上で昔に書かれた多くの教科書には、ヘッダーファイルで関数が宣言されていることがわかりました。新しいバージョンでは必要ないようです。デフォルトで生成されるフレームワークでは、ヘッダー ファイルに「PHP_FUNCTION(confirm_helloworld_compiled)」のような単語が表示されないためです。したがって、このファイルについてはあまり心配する必要はありません。 (ただし、実装する関数をヘッダー ファイルで宣言するのは良い習慣です)

helloworld.c 以下で使用されるバージョン番号がここで定義されていることに注意してください

#define PHP_HELLOWORLD_VERSION "0.1.0"
ログイン後にコピー

helloworld.c

コード構造

たくさんPHP_XXX のマクロは、main/php.h で定義された

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

##包含头文件(引入所需要的宏、API定义等)
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_helloworld.h"

static int le_helloworld;

##PHP核心定义的一个宏,与ZEND_FUNCTION相同,用于定义扩展函数(这个函数是系统默认生成的,用于确认之用)
PHP_FUNCTION(confirm_helloworld_compiled)
{
    char *arg = NULL;
    int arg_len, len;
    char *strg;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
        return;
    }

    len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "helloworld", arg);
    RETURN_STRINGL(strg, len, 0);
}

##定义PHP中可以调用的函数
PHP_FUNCTION(helloworld) {
    php_printf("Hello World!\n");
    RETURN_TRUE;
}

##初始化module时运行
PHP_MINIT_FUNCTION(helloworld)
{
    /* If you have INI entries, uncomment these lines 
    REGISTER_INI_ENTRIES();
    */
    return SUCCESS;
}

##当module被卸载时运行
PHP_MSHUTDOWN_FUNCTION(helloworld)
{
    /* uncomment this line if you have INI entries
    UNREGISTER_INI_ENTRIES();
    */
    return SUCCESS;
}

##当一个REQUEST请求初始化时运行
PHP_RINIT_FUNCTION(helloworld)
{
    return SUCCESS;
}

##当一个REQUEST请求结束时运行
PHP_RSHUTDOWN_FUNCTION(helloworld)
{
    return SUCCESS;
}

##声明模块信息函数,即可以在phpinfo看到的信息
PHP_MINFO_FUNCTION(helloworld)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "helloworld support", "enabled");
    php_info_print_table_end();

    /* Remove comments if you have entries in php.ini
    DISPLAY_INI_ENTRIES();
    */
}

##声明(引入)Zend(PHP)函数块
const zend_function_entry helloworld_functions[] = {
    PHP_FE(confirm_helloworld_compiled, NULL)       /* For testing, remove later. */
    ##上一讲中就是在这里添加了自己定义的函数模块
    PHP_FE(helloworld,  NULL)       /*  */
    ##zend引擎认为结束的标记,老版本的是“{NULL,NULL,NULL}”,后面PHP源代码直接定义了个宏PHP_FE_END,这里就直接用这个了。虽然都一个意思但看过去爽多了
    ##如果遇到PHP_FE_END未定义undefine的问题,请见附录1
    PHP_FE_END  /* Must be the last line in helloworld_functions[] */
};

##声明 Zend模块,是不是感觉下面的模块名字很熟悉,对的,就是前文讲到的PHP流程中会用到的,现在懂了为什么要先讲流程了吧~
zend_module_entry helloworld_module_entry = {
    STANDARD_MODULE_HEADER,
    "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),
    PHP_HELLOWORLD_VERSION,
    STANDARD_MODULE_PROPERTIES
};

##实现get_module()函数
#ifdef COMPILE_DL_HELLOWORLD
ZEND_GET_MODULE(helloworld)
#endif
ログイン後にコピー

モジュール構造です

1. ヘッダー ファイル (必要なマクロの導入、API 定義など) が含まれます。

モジュールに含める必要がある唯一のヘッダー ファイル。 php.h はメイン ディレクトリにあります。このファイルには、モジュールの構築に必要なさまざまなマクロと API 定義が含まれています。

2. エクスポートされた関数を宣言する (Zend 関数ブロックの宣言用);

ZEND_FUNCTION マクロは、Zend 内部 API を使用してコンパイルされた新しい C 関数を宣言します。この C 関数は void 型で、パラメータとして INTERNAL_FUNCTION_PARAMETERS (これは別のマクロ) を受け取り、関数名には zif_ という接頭辞が付きます。
PHP_FUNCTION はこれと同じです。 /main/php.h

#define PHP_FUNCTION            ZEND_FUNCTION
ログイン後にコピー

3 で Zend 関数ブロックを宣言します。

これでエクスポートされた関数を宣言しましたが、Zend はそれを呼び出す方法を知りません。したがって、Zend にも取り込む必要があります。これらの関数の導入は、N 個の zend_function_entry 構造体を含む配列によって完了します。配列内の各項目は外部から見える関数に対応し、各項目には PHP で表示される関数の名前と C コードで定義された名前が含まれます。

4. Zend モジュールを宣言します。

Zend モジュール情報は、Zend に提供する必要があるすべてのモジュール情報を含む zend_module_entry という構造体に保存されます。

5. get_module() 関数を実装します。

这个函数只用于动态可加载模块

6.实现导出函数。

实现想要扩展的函数,PHP_FUNCTION(helloworld)

ps:模块部分是学习这篇文章的,本来写好了,后面发现他写的比我好就借鉴了PHP扩展代码结构详解

附录

1.error: ‘PHP_FE_END’ undeclared here (not in a function)错误。

原因:是因为zend引擎版本太老了。
1、切换到php的源码目录,
2、执行下面两行

# sed -i 's|PHP_FE_END|{NULL,NULL,NULL}|' ./ext/**/*.c
# sed -i 's|ZEND_MOD_END|{NULL,NULL,NULL}|' ./ext/**/*.c
ログイン後にコピー

3.切换到mcrypt目录,如php-5.x.x/ext/mcrypt/。再次执行make命令,一切恢复正常。

以上がPHP拡張用拡張フレームワークの自動生成の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート