찾다
백엔드 개발PHP 튜토리얼PHP扩展开发-内核执行流程与扩展结构

在开发扩展之前,最好了解下PHP内核的执行流程,PHP大概包括三个方面:

SAPI
Zend VM
内部扩展

  • Zend VM是PHP的虚拟机,与JVM类似,都是各自语言的编译/执行的核心。它们都会把各自的代码先编译为一种中间代码,PHP的通常叫opcode,Java通常叫bytecode,不同的是PHP的opcode直接被Zend VM的执行单元调用对应的C函数执行,不会显示保留下来(可以cache保留),而Java通常是生成class文件保留下来。而这一点可能也是PHP interpreter的名称的由来吧。其实相对严格的C/C++等编译型语言,PHP和Java更多的是结合了编译型和解释性的风格。
  • SAPI可以看作是Zend VM向外界提供编译/执行PHP代码服务的方式和规范。无论是作为cli/cgi/fastcgi/apache_mod与其他程序交互,还是嵌入其他语言中如C/C++等,都可以通过SAPI的规范实现。它的一个重要数据结构就是sapi_module_struct(main/SAPI.h line 217)
  • 内部扩展部分可以看作是搭建在Zend VM和SAPI之上的库,为PHP开发人员提供性能和易用性上的保证。Java的各种包/Python的各种模块功能类似,不同的是PHP中为了性能是用C扩展来实现的,类似的在Java中可以通过JNI来实现,Python中如_socket和_select(多路复用)都不是原生Python实现。
  • 生命周期

    关于各种SAPI或者PHP本身的生命周期,可能会和其他组件如apache耦合,后续再细谈。关于PHP扩展的生命周期,这里借用一张图。流程应该是很容易明白的,关于这个过程,网上也有很多资料,不再赘述。我们开发扩展需要注意的几个地方也可以对应到图中的某些节点:

    全局变量的定义,通常是zend_modulename_globals
    模块的初始化,包括资源/类/常量/ini配置等模块级的初始化
    请求的初始化,包括与单次请求相关的一些初始化
    请求的结束,清理单次请求相关的数据/内存
    模块的卸载,清理模块相关的数据/内存

    基本上我们要做的就是按照上面的流程,实现相关的内置函数,定义自己的资源/全局变量/类/函数等。值得注意的地方是在在嵌入其他语言如Python或者被嵌入其他组件如apache时,要小心多进程多线程相关的问题。

    PHP扩展结构

    使用php-src/ext/ext_skel可以生成PHP扩展的框架

    ./ext_skel --extname=myext[tan@tan ~/software/needbak/php-5.5.20/ext 12:24]$==> ls myext/config.m4  config.w32  CREDITS  EXPERIMENTAL  myext.c  myext.php  php_myext.h  tests

    比较重要的文件是config.m4(当然还有源码),config.m4文件可以使用phpize命令生成configure文件,其中说明了我们是否开启模块,以及外部依赖的库。

    //config.m4//如果你的扩展依赖其他外部库dnl PHP_ARG_WITH(myext, for myext support,dnl Make sure that the comment is aligned:dnl [  --with-myext             Include myext support])//扩展不依赖外部库dnl PHP_ARG_ENABLE(myext, whether to enable myext support,dnl Make sure that the comment is aligned:dnl [  --enable-myext           Enable myext support])//寻找并包含头文件if test "$PHP_MYEXT" != "no"; then  dnl Write more examples of tests here...  dnl # --with-myext -> check with-path  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this  dnl SEARCH_FOR="/include/myext.h"  # you most likely want to change this  dnl if test -r $PHP_MYEXT/$SEARCH_FOR; then # path given as parameter  dnl   MYEXT_DIR=$PHP_MYEXT  dnl else # search default path list  dnl   AC_MSG_CHECKING([for myext files in default path])  dnl   for i in $SEARCH_PATH ; do  dnl     if test -r $i/$SEARCH_FOR; then  dnl       MYEXT_DIR=$i  dnl       AC_MSG_RESULT(found in $i)  dnl     fi  dnl   done  dnl fi  dnl  dnl if test -z "$MYEXT_DIR"; then  dnl   AC_MSG_RESULT([not found])  dnl   AC_MSG_ERROR([Please reinstall the myext distribution])  dnl fi  dnl # --with-myext -> add include path  dnl PHP_ADD_INCLUDE($MYEXT_DIR/include)  //加载的lib位置  dnl # --with-myext -> check for lib and symbol presence  dnl LIBNAME=myext # you may want to change this  dnl LIBSYMBOL=myext # you most likely want to change this   dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,  dnl [  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYEXT_DIR/$PHP_LIBDIR, MYEXT_SHARED_LIBADD)  dnl   AC_DEFINE(HAVE_MYEXTLIB,1,[ ])  dnl ],[  dnl   AC_MSG_ERROR([wrong myext lib version or lib not found])  dnl ],[  dnl   -L$MYEXT_DIR/$PHP_LIBDIR -lm  dnl ])  dnl  dnl PHP_SUBST(MYEXT_SHARED_LIBADD)  PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)fi
    //php_myext.h#ifndef PHP_MYEXT_H#define PHP_MYEXT_Hextern zend_module_entry myext_module_entry;#define phpext_myext_ptr &myext_module_entry//导出符号,在链接的时候有用#ifdef PHP_WIN32# define PHP_MYEXT_API __declspec(dllexport)#elif defined(__GNUC__) && __GNUC__ >= 4# define PHP_MYEXT_API __attribute__ ((visibility("default")))#else# define PHP_MYEXT_API#endif#ifdef ZTS#include "TSRM.h"#endif//几个核心函数的声明PHP_MINIT_FUNCTION(myext);PHP_MSHUTDOWN_FUNCTION(myext);PHP_RINIT_FUNCTION(myext);PHP_RSHUTDOWN_FUNCTION(myext);PHP_MINFO_FUNCTION(myext);//自动生成的测试函数声明,我们自己定义的模块函数需要在此声明PHP_FUNCTION(confirm_myext_compiled);   //全局变量在这定义,展开后是zend_myext_globals结构体ZEND_BEGIN_MODULE_GLOBALS(myext)    long  global_value;    char *global_string;ZEND_END_MODULE_GLOBALS(myext)//线程安全与非线程安全下获取全局变量的方式#ifdef ZTS#define MYEXT_G(v) TSRMG(myext_globals_id, zend_myext_globals *, v)#else#define MYEXT_G(v) (myext_globals.v)#endif#endif /* PHP_MYEXT_H */
    //myext.c#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_ini.h"#include "ext/standard/info.h"#include "php_myext.h"//全局变量声明ZEND_DECLARE_MODULE_GLOBALS(myext)/* True global resources - no need for thread safety here */static int le_myext;//模块函数的导出const zend_function_entry myext_functions[] = {    PHP_FE(confirm_myext_compiled,  NULL)       /* For testing, remove later. */    PHP_FE_END  /* Must be the last line in myext_functions[] */};//模块结构zend_module_entry myext_module_entry = {#if ZEND_MODULE_API_NO >= 20010901    STANDARD_MODULE_HEADER,#endif    "myext",    myext_functions,    PHP_MINIT(myext),    PHP_MSHUTDOWN(myext),    PHP_RINIT(myext),       /* Replace with NULL if there's nothing to do at request start */    PHP_RSHUTDOWN(myext),   /* Replace with NULL if there's nothing to do at request end */    PHP_MINFO(myext),#if ZEND_MODULE_API_NO >= 20010901    PHP_MYEXT_VERSION,#endif    STANDARD_MODULE_PROPERTIES};#ifdef COMPILE_DL_MYEXTZEND_GET_MODULE(myext)#endif//ini配置文件的设置PHP_INI_BEGIN()    STD_PHP_INI_ENTRY("myext.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_myext_globals, myext_globals)    STD_PHP_INI_ENTRY("myext.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_myext_globals, myext_globals)PHP_INI_END()//初始化全局变量static void php_myext_init_globals(zend_myext_globals *myext_globals){    myext_globals->global_value = 0;    myext_globals->global_string = NULL;}//模块加载时的函数PHP_MINIT_FUNCTION(myext){    /* If you have INI entries, uncomment these lines REGISTER_INI_ENTRIES(); */    return SUCCESS;}//模块卸载时函数PHP_MSHUTDOWN_FUNCTION(myext){    /* uncomment this line if you have INI entries UNREGISTER_INI_ENTRIES(); */    return SUCCESS;}//请求初始化函数PHP_RINIT_FUNCTION(myext){    return SUCCESS;}//请求关闭函数PHP_RSHUTDOWN_FUNCTION(myext){    return SUCCESS;}//模块信息,phpinfoPHP_MINFO_FUNCTION(myext){    php_info_print_table_start();    php_info_print_table_header(2, "myext support", "enabled");    php_info_print_table_end();    /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */}//测试函数PHP_FUNCTION(confirm_myext_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.", "myext", arg);    RETURN_STRINGL(strg, len, 0);}
    성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    과대 광고 : 오늘 PHP의 역할을 평가합니다과대 광고 : 오늘 PHP의 역할을 평가합니다Apr 12, 2025 am 12:17 AM

    PHP는 현대적인 프로그래밍, 특히 웹 개발 분야에서 강력하고 널리 사용되는 도구로 남아 있습니다. 1) PHP는 사용하기 쉽고 데이터베이스와 완벽하게 통합되며 많은 개발자에게 가장 먼저 선택됩니다. 2) 동적 컨텐츠 생성 및 객체 지향 프로그래밍을 지원하여 웹 사이트를 신속하게 작성하고 유지 관리하는 데 적합합니다. 3) 데이터베이스 쿼리를 캐싱하고 최적화함으로써 PHP의 성능을 향상시킬 수 있으며, 광범위한 커뮤니티와 풍부한 생태계는 오늘날의 기술 스택에 여전히 중요합니다.

    PHP의 약한 참고 자료는 무엇이며 언제 유용합니까?PHP의 약한 참고 자료는 무엇이며 언제 유용합니까?Apr 12, 2025 am 12:13 AM

    PHP에서는 약한 참조가 약한 회의 클래스를 통해 구현되며 쓰레기 수집가가 물체를 되 찾는 것을 방해하지 않습니다. 약한 참조는 캐싱 시스템 및 이벤트 리스너와 같은 시나리오에 적합합니다. 물체의 생존을 보장 할 수 없으며 쓰레기 수집이 지연 될 수 있음에 주목해야합니다.

    PHP의 __invoke 마법 방법을 설명하십시오.PHP의 __invoke 마법 방법을 설명하십시오.Apr 12, 2025 am 12:07 AM

    \ _ \ _ 호출 메소드를 사용하면 객체를 함수처럼 호출 할 수 있습니다. 1. 객체를 호출 할 수 있도록 메소드를 호출하는 \ _ \ _ 정의하십시오. 2. $ obj (...) 구문을 사용할 때 PHP는 \ _ \ _ invoke 메소드를 실행합니다. 3. 로깅 및 계산기, 코드 유연성 및 가독성 향상과 같은 시나리오에 적합합니다.

    동시성에 대해 PHP 8.1의 섬유를 설명하십시오.동시성에 대해 PHP 8.1의 섬유를 설명하십시오.Apr 12, 2025 am 12:05 AM

    섬유는 PHP8.1에 도입되어 동시 처리 기능을 향상시켰다. 1) 섬유는 코 루틴과 유사한 가벼운 동시성 모델입니다. 2) 개발자는 작업의 실행 흐름을 수동으로 제어 할 수 있으며 I/O 집약적 작업을 처리하는 데 적합합니다. 3) 섬유를 사용하면보다 효율적이고 반응이 좋은 코드를 작성할 수 있습니다.

    PHP 커뮤니티 : 자원, 지원 및 개발PHP 커뮤니티 : 자원, 지원 및 개발Apr 12, 2025 am 12:04 AM

    PHP 커뮤니티는 개발자 성장을 돕기 위해 풍부한 자원과 지원을 제공합니다. 1) 자료에는 공식 문서, 튜토리얼, 블로그 및 Laravel 및 Symfony와 같은 오픈 소스 프로젝트가 포함됩니다. 2) 지원은 StackoverFlow, Reddit 및 Slack 채널을 통해 얻을 수 있습니다. 3) RFC에 따라 개발 동향을 배울 수 있습니다. 4) 적극적인 참여, 코드에 대한 기여 및 학습 공유를 통해 커뮤니티에 통합 될 수 있습니다.

    PHP vs. Python : 차이점 이해PHP vs. Python : 차이점 이해Apr 11, 2025 am 12:15 AM

    PHP와 Python은 각각 고유 한 장점이 있으며 선택은 프로젝트 요구 사항을 기반으로해야합니다. 1.PHP는 간단한 구문과 높은 실행 효율로 웹 개발에 적합합니다. 2. Python은 간결한 구문 및 풍부한 라이브러리를 갖춘 데이터 과학 및 기계 학습에 적합합니다.

    PHP : 죽어 가거나 단순히 적응하고 있습니까?PHP : 죽어 가거나 단순히 적응하고 있습니까?Apr 11, 2025 am 12:13 AM

    PHP는 죽지 않고 끊임없이 적응하고 진화합니다. 1) PHP는 1994 년부터 새로운 기술 트렌드에 적응하기 위해 여러 버전 반복을 겪었습니다. 2) 현재 전자 상거래, 컨텐츠 관리 시스템 및 기타 분야에서 널리 사용됩니다. 3) PHP8은 성능과 현대화를 개선하기 위해 JIT 컴파일러 및 기타 기능을 소개합니다. 4) Opcache를 사용하고 PSR-12 표준을 따라 성능 및 코드 품질을 최적화하십시오.

    PHP의 미래 : 적응 및 혁신PHP의 미래 : 적응 및 혁신Apr 11, 2025 am 12:01 AM

    PHP의 미래는 새로운 기술 트렌드에 적응하고 혁신적인 기능을 도입함으로써 달성 될 것입니다. 1) 클라우드 컴퓨팅, 컨테이너화 및 마이크로 서비스 아키텍처에 적응, Docker 및 Kubernetes 지원; 2) 성능 및 데이터 처리 효율을 향상시키기 위해 JIT 컴파일러 및 열거 유형을 도입합니다. 3) 지속적으로 성능을 최적화하고 모범 사례를 홍보합니다.

    See all articles

    핫 AI 도구

    Undresser.AI Undress

    Undresser.AI Undress

    사실적인 누드 사진을 만들기 위한 AI 기반 앱

    AI Clothes Remover

    AI Clothes Remover

    사진에서 옷을 제거하는 온라인 AI 도구입니다.

    Undress AI Tool

    Undress AI Tool

    무료로 이미지를 벗다

    Clothoff.io

    Clothoff.io

    AI 옷 제거제

    AI Hentai Generator

    AI Hentai Generator

    AI Hentai를 무료로 생성하십시오.

    인기 기사

    R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
    3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 최고의 그래픽 설정
    3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
    3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
    4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

    뜨거운 도구

    스튜디오 13.0.1 보내기

    스튜디오 13.0.1 보내기

    강력한 PHP 통합 개발 환경

    WebStorm Mac 버전

    WebStorm Mac 버전

    유용한 JavaScript 개발 도구

    맨티스BT

    맨티스BT

    Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

    SublimeText3 Linux 새 버전

    SublimeText3 Linux 새 버전

    SublimeText3 Linux 최신 버전

    메모장++7.3.1

    메모장++7.3.1

    사용하기 쉬운 무료 코드 편집기