Heim  >  Artikel  >  Backend-Entwicklung  >  Automatische Generierung eines Erweiterungsframeworks für PHP-Erweiterungen

Automatische Generierung eines Erweiterungsframeworks für PHP-Erweiterungen

黄舟
黄舟Original
2017-08-14 09:32:121996Durchsuche

Vorwort

Vorheriger Artikel: Anfänger lernt PHP-Erweiterung – hallo Welt Egal aus welchem ​​Grund, er sagt gewaltsam Hallo zur PHP-Erweiterung. Das von ext_skel automatisch generierte Framework wird in diesem Artikel als Memo ausführlich erläutert.

Text

Verwendung von 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 und erweiterungsbezogene Prozesse

1. Der Start und die Beendigung von PHP-Programmen sind dort konzeptionell unterschiedlich sind zwei.

Zum einen wird beim Laden des PHP-Moduls die Modulstartfunktion von der Engine aufgerufen (PHP_MINIT_FUNCTION). Dadurch kann die Engine einige Initialisierungen wie Ressourcentypen, Registrierung von INI-Variablen usw. durchführen, und diese Daten sind im Speicher resident, was einer Beendigung entspricht (PHP_MSHUTDOWN_FUNCTION)

Die andere ist, wenn die PHP-Anfrage startet, die Anfrage Rufen Sie nicht die vorherige Startfunktion (PHP_RINIT_FUNCTION) auf, die der Beendigung nach Abschluss der Anfrage entspricht (PHP_RSHUTDOWN_FUNCTION)

2. Wenn PHP startet, beginnt es mit der Verarbeitung aller seiner MINIT-Methoden geladene Erweiterungen. (Der vollständige Name ist Modulinitialisierung, eine von jedem Modul definierte Funktion.) (PHP_MINIT_FUNCTION), während dieser Zeit kann die Erweiterung einige ihrer eigenen Konstanten, Klassen, Ressourcen usw. definieren. All dies wird vom benutzerseitigen PHP-Skript verwendet. Die hier definierten Inhalte bleiben im Speicher und können von allen Anfragen verwendet werden, bis das PHP-Modul ausgeschaltet wird.

3. Wenn eine Anfrage eingeht, öffnet PHP schnell eine neue Umgebung, scannt seine eigenen Erweiterungen erneut und führt ihre jeweiligen RINIT-Methoden (vollständiger Name Request Initialization) aus (PHP_RINIT_FUNCTION). Die Erweiterung kann Variablen initialisieren, die in dieser Anfrage usw. verwendet werden, und kann später auch Variablen im Client (z. B. PHP-Skript) usw. initialisieren.

4. Wenn die Anfrage den Geschäftscode durchläuft und bis zum Ende ausgeführt wird, startet PHP das Recyclingprogramm und führt die Methode RSHUTDOWN (vollständiger Name Request Shutdown) (PHP_RSHUTDOWN_FUNCTION) unter Verwendung von Variablen aus Machen Sie im Kernel so etwas wie eine Tabelle. Sobald die Ausführung abgeschlossen ist, wird alles, was in dieser Anfrage verwendet wird, freigegeben, einschließlich aller Variablen in der Variablentabelle, des gesamten in dieser Anfrage angeforderten Speichers usw.

5 Danach Die Anforderungsverarbeitung ist abgeschlossen, diejenigen, die geschlossen werden sollten, werden ebenfalls geschlossen, und PHP tritt in die Phase MSHUTDOWN (vollständiger Name des Moduls Shutdown) (PHP_MSHUTDOWN_FUNCTION) ein. Zu diesem Zeitpunkt stellt PHP allen Erweiterungen ein Ultimatum hat unerfüllte Wünsche, lassen Sie es los. In seiner eigenen MSHUTDOWN-Methode ist dies die letzte Chance. Sobald PHP die Ausführung des erweiterten MSHUTDOWN beendet hat, tritt es in das Selbstzerstörungsprogramm ein. (Letzte Chance, nicht autorisierten Speicher zu löschen, sonst geht Speicher verloren)

Zusammenfassung, der Prozess, den ich verstehe:
PHP_MINIT_FUNCTION (wird einmal pro Prozess ausgeführt)
|.
Führen Sie viele PHP_RINIT_FUNCTION
aus |.
Führen Sie viele PHP_RSHUTDOWN_FUNCTION
aus |.
PHP_MSHUTDOWN_FUNCTION (wird einmal pro Prozess ausgeführt)

Anbei sind die Diagramme von Multi-Threading und Multi-Prozess
Automatische Generierung eines Erweiterungsframeworks für PHP-Erweiterungen

Automatische Generierung eines Erweiterungsframeworks für PHP-Erweiterungen

config.m4

dnl bedeutet, diese Zeile auskommentieren, genau wie // in PHP. Ich werde nicht untersuchen, warum es DNL ist, ich weiß nur, dass es eine Notiz ist.

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

Ich habe festgestellt, dass in vielen Lehrbüchern, die vor langer Zeit im Internet geschrieben wurden, Funktionen in der Header-Datei deklariert sind. Es scheint, dass neuere Versionen dies nicht erfordern. Weil das standardmäßig generierte Framework keine Wörter wie „PHP_FUNCTION(confirm_helloworld_compiled)“ in der Header-Datei sieht. Machen Sie sich also keine allzu großen Sorgen um diese Datei. (Es empfiehlt sich jedoch, die zu implementierende Funktion in der Header-Datei zu deklarieren.)

Beachten Sie, dass die Versionsnummer, die unter helloworld.c verwendet wird, hier definiert ist

#define PHP_HELLOWORLD_VERSION "0.1.0"

helloworld.c

Codestruktur

Viele Makros von PHP_XXX sind in main/php.h definiert

#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

Modulstruktur

1 Dateien (Führen Sie die erforderlichen Makros, API-Definitionen usw. ein); die Header-Datei, die das Modul

enthalten muss, ist nur eine php.h, die sich im Hauptverzeichnis befindet. Diese Datei enthält verschiedene Makros und API-Definitionen, die zum Erstellen des Moduls erforderlich sind.

2. Exportierte Funktionen deklarieren (zur Deklaration von Zend-Funktionsblöcken);

Das Makro ZEND_FUNCTION deklariert eine neue C-Funktion, die mit der internen Zend-API kompiliert wurde. Diese C-Funktion ist vom Typ void, verwendet INTERNAL_FUNCTION_PARAMETERS (dies ist ein weiteres Makro) als Parameter und dem Funktionsnamen wird zif_ vorangestellt.
PHP_FUNCTION ist dasselbe und das Makro wurde in /main/php.h definiert

#define PHP_FUNCTION            ZEND_FUNCTION

3. Deklarieren Sie den Zend-Funktionsblock

Jetzt haben Sie ihn deklariert Die Funktion wird exportiert, aber Zend weiß nicht, wie sie aufgerufen werden soll, daher muss sie in Zend importiert werden. Die Einführung dieser Funktionen wird durch ein Array mit N zend_function_entry-Strukturen vervollständigt. Jedes Element im Array entspricht einer extern sichtbaren Funktion, und jedes Element enthält den Namen einer Funktion, wie er in PHP erscheint, und den im C-Code definierten Namen.

4. Deklarieren Sie das Zend-Modul.

Die Zend-Modulinformationen werden in einer Struktur namens zend_module_entry gespeichert, die alle Modulinformationen enthält, die Zend bereitgestellt werden müssen.

5. Implementieren Sie die Funktion 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命令,一切恢复正常。

Das obige ist der detaillierte Inhalt vonAutomatische Generierung eines Erweiterungsframeworks für PHP-Erweiterungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn