PHP解释器引擎执行流程
catalogue
1. SAPI接口2. PHP CLI模式解释执行脚本流程3. PHP Zend Complile/Execute函数接口化(Hook Call架构基础)
1. SAPI接口
PHP的SAPI层实现上层接口的封装,使得PHP可以用在很多种模式场景下(例如apache、ningx、cgi、fastcgi、cli),以以cli SAPI为例子学习PHP解释器引擎是如何处理PHP用户态源代码文件的Cli(Command Line Interface)即PHP的命令行模式,现在此SAPI是默认安装的,我们在服务器上安装完PHP之后,一般会生成一个可执行文件
脚本执行的开始都是以SAPI接口实现开始的。只是不同的SAPI接口实现会完成他们特定的工作, 例如Apache的mod_php SAPI实现需要初始化从Apache获取的一些信息,在输出内容是将内容返回给Apache, 其他的SAPI实现也类似
0x1: sapi_module_struct
要定义个SAPI,首先要定义个sapi_module_structPHP-SRC/sapi/cli/php_cli.c
/* {{{ sapi_module_struct cli_sapi_module */static sapi_module_struct cli_sapi_module = { "cli", /* name php_info()的时候被使用 */ "Command Line Interface", /* pretty name */ php_cli_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ sapi_cli_deactivate, /* deactivate */ sapi_cli_ub_write, /* unbuffered write */ sapi_cli_flush, /* flush */ NULL, /* get uid */ NULL, /* getenv */ php_error, /* error handler */ sapi_cli_header_handler, /* header handler */ sapi_cli_send_headers, /* send headers handler */ sapi_cli_send_header, /* send header handler */ NULL, /* read POST data */ sapi_cli_read_cookies, /* read Cookies */ sapi_cli_register_variables, /* register server variables */ sapi_cli_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES};/* }}} */
这个结构,包含了一些常量,比如name, 这个会在我们调用php_info()的时候被使用。一些初始化,收尾函数,以及一些函数指针,用来告诉Zend,如何获取,和输出数据,我们在下面的流程介绍中就会逐个涉及到其中的字段
Relevant Link:
http://www.nowamagic.net/librarys/veda/detail/1285
2. PHP CLI模式解释执行脚本流程
0x1: Process Startup
主进程main在进行一些必要的初始化工作后,就进入SAPI的逻辑流程, 初始化的一些环境变量,这将在整个SAPI生命周期中发生作用
0x2: MINIT
进入特定的SAPI模式之后,PHP调用各个扩展的MINIT方法 \php-5.6.17\sapi\cli\php_cli.c
int main(int argc, char *argv[]){ .. sapi_module_struct *sapi_module = &cli_sapi_module; .. sapi_module->ini_defaults = sapi_cli_ini_defaults; sapi_module->php_ini_path_override = ini_path_override; sapi_module->phpinfo_as_text = 1; sapi_module->php_ini_ignore_cwd = 1; sapi_startup(sapi_module); sapi_started = 1; ..
php_cli_startup
static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */{ if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { return FAILURE; } return SUCCESS;}
PHP调用各个扩展的MINIT方法,从而使这些扩展切换到可用状态
/* {{{ php_module_startup */int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules){ .. zend_module_entry *module; .. module_shutdown = 0; module_startup = 1; sapi_initialize_empty_request(TSRMLS_C); sapi_activate(TSRMLS_C); .. /* start additional PHP extensions */ php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC); /* load and startup extensions compiled as shared objects (aka DLLs) as requested by php.ini entries theese are loaded after initialization of internal extensions as extensions *might* rely on things from ext/standard which is always an internal extension and to be initialized ahead of all other internals */ php_ini_register_extensions(TSRMLS_C); zend_startup_modules(TSRMLS_C); /* start Zend extensions */ zend_startup_extensions(); ..
MINIT的意思是"模块初始化"。各个模块都定义了一组函数、类库等用以处理其他请求一个典型的MINIT方法如下
PHP_MINIT_FUNCTION(extension_name){ /* Initialize functions, classes etc */ }
0x3: RINIT
当一个页面请求发生时,SAPI层将控制权交给PHP层。于是PHP设置了用于回复本次请求所需的环境变量。同时,它还建立一个变量表,用来存放执行过程 中产生的变量名和值。PHP调用各个模块的RINIT方法,即"请求初始化"
一个经典的例子是Session模块的RINIT,如果在php.ini中 启用了Session模块,那在调用该模块的RINIT时就会初始化$_SESSION变量,并将相关内容读入
RINIT方法可以看作是一个准备过程, 在程序执行之前就会自动启动。一个典型的RINIT方法如下
PHP_RINIT_FUNCTION(extension_name) { /* Initialize session variables,pre-populate variables, redefine global variables etc */ }
PHP会在每个request的时候,处理一些初始化,资源分配的事务。这部分就是activate字段要定义的,从上面的结构我们可以看出,从上面cli对应的cli_sapi_module结构体来看,对于CGI来说,它并没有提供初始化处理句柄。对于mod_php来说,那就不同了,他要在apache的pool中注册资源析构函数,申请空间, 初始化环境变量,等等
0x4: SCRIPT
PHP通过php_execute_script(&file_handle TSRMLS_CC)来执行PHP的脚本 \php-5.6.17\main\main.c
/* {{{ php_execute_script */PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC){ //file_handle的类型为zend_file_handle,这个是zend对文件句柄的一个封装,里面的内容和待执行脚本相关 zend_file_handle *prepend_file_p, *append_file_p; zend_file_handle prepend_file = {0}, append_file = {0}; .. //php_execute_script最终是调用的zend_execute_scripts retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS); ..
php_execute_script最终是调用的zend_execute_scripts{PHPSRC}/Zend/zend.c
//此函数具有可变参数,可以一次执行多个PHP文件ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) /* {{{ */{ .. EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC); .. if (EG(active_op_array)) { EG(return_value_ptr_ptr) = retval ? retval : NULL; zend_execute(EG(active_op_array) TSRMLS_CC); ..
1. compile编译过程
zend_compile_file是一个函数指针,其声明在{PHPSRC}/Zend/zend_compile.c中
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
在引擎初始化的时候,会将compile_file函数的地址赋值给zend_compile_file,compile_file函数定义在{PHPSRC}/Zend/zend_language_scanner.l
//函数以zend_file_handle指针作为参数,返回一个指向zend_op_array的指针ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC){ .. //Lex词法解析过程 ..
2. execute执行过程(逐条执行opcode)
zend_execute也是一个函数指针(利用compile过程得到的opcode array),其声明在{PHPSRC}/Zend/zend_execute.c
ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
在引擎初始化的时候,会将execute函数的地址赋值给zend_execute,execute的定义在{PHPSRC}/Zend/zend_vm_execute.h
//zend_execute以一个指向zend_op_array结构的指针作为参数,这个指针即前面zend_compile_file的返回值,zend_execute就开始执行op_array中的op code,在执行op code的过程中,就实现了PHP语言的各种功能ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC){ if (EG(exception)) { return; } zend_execute_ex(i_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);}
0x5: RSHUTDOWN
一旦页面执行完毕(无论是执行到了文件末尾还是用exit或die函数中止),PHP就会启动清理程序。它会按顺序调用各个模块的RSHUTDOWN方法。 RSHUTDOWN用以清除程序运行时产生的符号表,也就是对每个变量调用unset函数
PHP_RSHUTDOWN_FUNCTION(extension_name) { /* Do memory management, unset all variables used in the last PHP call etc */ }
0x6: MSHUTDOWN
最后,所有的请求都已处理完毕,SAPI也准备关闭了,PHP开始执行第二步:PHP调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会
PHP_MSHUTDOWN_FUNCTION(extension_name) { /* Free handlers and persistent memory etc */ }
/main/main.c
/* {{{ php_module_shutdown_wrapper */int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals){ TSRMLS_FETCH(); php_module_shutdown(TSRMLS_C); return SUCCESS;}
Relevant Link:
http://www.nowamagic.net/librarys/veda/detail/1286http://www.nowamagic.net/librarys/veda/detail/1322http://www.nowamagic.net/librarys/veda/detail/1323http://www.nowamagic.net/librarys/veda/detail/1332http://blog.csdn.net/phpkernel/article/details/5716342http://www.nowamagic.net/librarys/veda/detail/1287http://www.nowamagic.net/librarys/veda/detail/1289
3. PHP Zend Complile/Execute函数接口化(Hook Call架构基础)
PHP内核在设计架构实现的时候,除了提供了扩展机制,还在Zend的两个关键流程(compile、execute)提供了Hook机制,PHP扩展开发人员可以Hook劫持Zend的编译/解释执行流程,在Zend编译执行之前先执行自定义的代码逻辑,然后再交还控制权给Zend。在引擎初始化(zend_startup)的时候
1. end_execute指向了默认的execute2. zend_compile_file指向了默认的compile_file
我们可以在实际编译和执行之前(RINIT阶段中)将zend_execute和zend_compile_file重写为其他的编译和执行函数,这样就为我们扩展引擎留下了钩子,比如一个比较有名的查看PHP的op code的扩展vld,此扩展就是在每次请求初始化的钩子函数(PHP_RINIT_FUNCTION)中,将zend_execute和zend_compile_file替换成自己的vld_execute和vld_compile_file,这两个函数其实是对原始函数进行了封装,添加了输出opcode信息的附加功能,因为引擎初始化是发生在模块请求初始化之前,而模块请求初始化又是在编译和执行之前,所以这样的覆盖能达到目的
Relevant Link:
Copyright (c) 2016 LittleHann All rights reserved

핫 AI 도구

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

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

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











종종 키워드와 추적 매개 변수로 혼란스러워하는 긴 URL은 방문자를 방해 할 수 있습니다. URL 단축 스크립트는 솔루션을 제공하여 소셜 미디어 및 기타 플랫폼에 이상적인 간결한 링크를 만듭니다. 이 스크립트는 개별 웹 사이트 a에 유용합니다

Instagram은 2012 년 Facebook에서 유명한 인수에 이어 타사 사용을 위해 두 개의 API 세트를 채택했습니다. Instagram Graph API 및 Instagram Basic Display API입니다. 개발자는

Laravel은 직관적 인 플래시 방법을 사용하여 임시 세션 데이터 처리를 단순화합니다. 응용 프로그램에 간단한 메시지, 경고 또는 알림을 표시하는 데 적합합니다. 데이터는 기본적으로 후속 요청에만 지속됩니다. $ 요청-

이것은 Laravel 백엔드가있는 React Application을 구축하는 데있어 시리즈의 두 번째이자 마지막 부분입니다. 이 시리즈의 첫 번째 부분에서는 기본 제품 목록 응용 프로그램을 위해 Laravel을 사용하여 편안한 API를 만들었습니다. 이 튜토리얼에서는 Dev가 될 것입니다

Laravel은 간결한 HTTP 응답 시뮬레이션 구문을 제공하여 HTTP 상호 작용 테스트를 단순화합니다. 이 접근법은 테스트 시뮬레이션을보다 직관적으로 만들면서 코드 중복성을 크게 줄입니다. 기본 구현은 다양한 응답 유형 단축키를 제공합니다. Illuminate \ support \ Facades \ http를 사용하십시오. http :: 가짜 ([ 'google.com'=> 'Hello World', 'github.com'=> [ 'foo'=> 'bar'], 'forge.laravel.com'=>

PHP 클라이언트 URL (CURL) 확장자는 개발자를위한 강력한 도구이며 원격 서버 및 REST API와의 원활한 상호 작용을 가능하게합니다. PHP CURL은 존경받는 다중 프로모토콜 파일 전송 라이브러리 인 Libcurl을 활용하여 효율적인 execu를 용이하게합니다.

고객의 가장 긴급한 문제에 실시간 인스턴트 솔루션을 제공하고 싶습니까? 라이브 채팅을 통해 고객과 실시간 대화를 나누고 문제를 즉시 해결할 수 있습니다. 그것은 당신이 당신의 관습에 더 빠른 서비스를 제공 할 수 있도록합니다.

2025 PHP Landscape Survey는 현재 PHP 개발 동향을 조사합니다. 개발자와 비즈니스에 대한 통찰력을 제공하는 프레임 워크 사용, 배포 방법 및 과제를 탐색합니다. 이 조사는 현대 PHP Versio의 성장을 예상합니다
