>백엔드 개발 >PHP 튜토리얼 >PHP 확장을 위한 확장 프레임워크 자동 생성

PHP 확장을 위한 확장 프레임워크 자동 생성

黄舟
黄舟원래의
2017-08-14 09:32:122015검색

머리말

이전 기사: 초보자는 PHP 확장을 배웁니다. Hello World 이유를 불문하고 강제로 PHP 확장에 대해 인사합니다. ext_skel에 의해 자동으로 생성되는 프레임워크는 본 글에서 메모로 자세히 설명하도록 하겠습니다.

Text

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 프로그램의 시작과 종료는 두 가지로 구분됩니다.

하나는 PHP 모듈이 로드될 때 엔진(PHP_MINIT_FUNCTION)에 의해 모듈 시작 함수가 호출된다는 것입니다. 이를 통해 엔진은 리소스 유형, INI 변수 등록 등과 같은 일부 초기화를 수행할 수 있으며 이러한 데이터는 종료에 따라 메모리에 상주합니다(PHP_MSHUTDOWN_FUNCTION)

다른 하나는 PHP 요청이 시작될 때, 시작 기능이 시작되기 전에 요청이 완료된 후 종료에 해당하는 (PHP_RINIT_FUNCTION)을 호출하세요(PHP_RSHUTDOWN_FUNCTION)

2. PHP가 시작되면 로드된 모든 확장의 MINIT 메서드(전체 이름: 모듈 초기화)를 처리하기 시작합니다. )(PHP_MINIT_FUNCTION)이 한 번 실행됩니다. 이 시간 동안 확장 프로그램은 사용자 측 PHP 스크립트에서 사용할 자체 상수, 클래스, 리소스 등을 정의할 수 있습니다. 여기에 정의된 내용은 메모리에 상주하며 PHP 모듈이 꺼질 때까지 모든 요청에서 사용할 수 있습니다.

3. 요청이 오면 PHP는 신속하게 새로운 환경을 열고 자체 확장을 다시 검색한 다음 해당 RINIT 메서드(전체 이름 요청 초기화)(PHP_RINIT_FUNCTION)를 탐색하고 실행합니다. 이 요청에 사용될 변수 등은 나중에 클라이언트(즉, PHP 스크립트) 변수 등에서도 초기화됩니다.

4. 요청이 비즈니스 코드를 통과하여 끝까지 실행되면 PHP는 재활용 프로그램을 시작하고 로드된 모든 확장 프로그램의 RSHUTDOWN(전체 이름 Request Shutdown)(PHP_RSHUTDOWN_FUNCTION) 메서드를 실행합니다. 실행이 완료되면 변수 테이블의 모든 변수, 이 요청에 적용된 모든 메모리 등을 포함하여 이 요청에 사용된 모든 것이 해제됩니다. 완료되면 닫을 시간입니다. PHP는 MSHUTDOWN(전체 이름 모듈 종료)(PHP_MSHUTDOWN_FUNCTION) 단계에 들어갑니다. 이 때 PHP는 모든 확장에 대해 최후통첩을 보냅니다. 이것이 마지막 기회입니다. PHP가 확장된 MSHUTDOWN 실행을 마치면 자체 소멸 프로그램에 들어갑니다. (승인 없이 신청한 메모리를 지울 수 있는 마지막 기회입니다. 그렇지 않으면 메모리가 누출됩니다.)

제가 이해하는 프로세스 요약:

PHP_MINIT_FUNCTION(프로세스당 한 번 실행)


| 많은 PHP_RINIT_FUNCTION을 실행하세요

| 많은 PHP_RSHUTDOWN_FUNCTION을 실행하세요

| PHP_MSHUTDOWN_FUNCTION(프로세스당 한 번 실행)

멀티 스레딩 및 멀티 프로세스 다이어그램이 첨부되어 있습니다.


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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.