Jadual Kandungan
catalogue
1. SAPI接口
Relevant Link:
2. PHP CLI模式解释执行脚本流程
Copyright (c) 2016 LittleHann All rights reserved
Rumah pembangunan bahagian belakang tutorial php PHP解释器引擎执行流程

PHP解释器引擎执行流程

Jun 23, 2016 pm 01:17 PM

catalogue

1. SAPI接口2. PHP CLI模式解释执行脚本流程3. PHP Zend Complile/Execute函数接口化(Hook Call架构基础)
Salin selepas log masuk

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};/* }}} */
Salin selepas log masuk

这个结构,包含了一些常量,比如name, 这个会在我们调用php_info()的时候被使用。一些初始化,收尾函数,以及一些函数指针,用来告诉Zend,如何获取,和输出数据,我们在下面的流程介绍中就会逐个涉及到其中的字段

http://www.nowamagic.net/librarys/veda/detail/1285
Salin selepas log masuk

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;    ..
Salin selepas log masuk

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;}
Salin selepas log masuk

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();    ..
Salin selepas log masuk

MINIT的意思是"模块初始化"。各个模块都定义了一组函数、类库等用以处理其他请求一个典型的MINIT方法如下

PHP_MINIT_FUNCTION(extension_name){ /* Initialize functions, classes etc */ }
Salin selepas log masuk

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 */ }
Salin selepas log masuk

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);    ..
Salin selepas log masuk

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);        ..
Salin selepas log masuk

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);  
Salin selepas log masuk

在引擎初始化的时候,会将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词法解析过程    ..
Salin selepas log masuk

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);  
Salin selepas log masuk

在引擎初始化的时候,会将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);}
Salin selepas log masuk

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 */ }
Salin selepas log masuk

0x6: MSHUTDOWN

最后,所有的请求都已处理完毕,SAPI也准备关闭了,PHP开始执行第二步:PHP调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会

PHP_MSHUTDOWN_FUNCTION(extension_name) { /* Free handlers and persistent memory etc */ }
Salin selepas log masuk

/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;}
Salin selepas log masuk
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
Salin selepas log masuk

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
Salin selepas log masuk

我们可以在实际编译和执行之前(RINIT阶段中)将zend_execute和zend_compile_file重写为其他的编译和执行函数,这样就为我们扩展引擎留下了钩子,比如一个比较有名的查看PHP的op code的扩展vld,此扩展就是在每次请求初始化的钩子函数(PHP_RINIT_FUNCTION)中,将zend_execute和zend_compile_file替换成自己的vld_execute和vld_compile_file,这两个函数其实是对原始函数进行了封装,添加了输出opcode信息的附加功能,因为引擎初始化是发生在模块请求初始化之前,而模块请求初始化又是在编译和执行之前,所以这样的覆盖能达到目的

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bekerja dengan Data Sesi Flash di Laravel Bekerja dengan Data Sesi Flash di Laravel Mar 12, 2025 pm 05:08 PM

Laravel memudahkan mengendalikan data sesi sementara menggunakan kaedah flash intuitifnya. Ini sesuai untuk memaparkan mesej ringkas, makluman, atau pemberitahuan dalam permohonan anda. Data hanya berterusan untuk permintaan seterusnya secara lalai: $ permintaan-

Curl dalam PHP: Cara Menggunakan Pelanjutan PHP Curl dalam API REST Curl dalam PHP: Cara Menggunakan Pelanjutan PHP Curl dalam API REST Mar 14, 2025 am 11:42 AM

Pelanjutan URL Pelanggan PHP (CURL) adalah alat yang berkuasa untuk pemaju, membolehkan interaksi lancar dengan pelayan jauh dan API rehat. Dengan memanfaatkan libcurl, perpustakaan pemindahan fail multi-protokol yang dihormati, php curl memudahkan execu yang cekap

Respons HTTP yang dipermudahkan dalam ujian Laravel Respons HTTP yang dipermudahkan dalam ujian Laravel Mar 12, 2025 pm 05:09 PM

Laravel menyediakan sintaks simulasi respons HTTP ringkas, memudahkan ujian interaksi HTTP. Pendekatan ini dengan ketara mengurangkan redundansi kod semasa membuat simulasi ujian anda lebih intuitif. Pelaksanaan asas menyediakan pelbagai jenis pintasan jenis tindak balas: Gunakan Illuminate \ Support \ Facades \ http; Http :: palsu ([ 'Google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

Cari muat turun fail di laravel dengan penyimpanan :: muat turun Cari muat turun fail di laravel dengan penyimpanan :: muat turun Mar 06, 2025 am 02:22 AM

Penyimpanan :: Kaedah Muat turun Rangka Kerja Laravel menyediakan API ringkas untuk mengendalikan muat turun fail dengan selamat sambil menguruskan abstraksi penyimpanan fail. Berikut adalah contoh menggunakan penyimpanan :: muat turun () dalam pengawal contoh:

12 skrip sembang php terbaik di codecanyon 12 skrip sembang php terbaik di codecanyon Mar 13, 2025 pm 12:08 PM

Adakah anda ingin memberikan penyelesaian segera, segera kepada masalah yang paling mendesak pelanggan anda? Sembang langsung membolehkan anda mempunyai perbualan masa nyata dengan pelanggan dan menyelesaikan masalah mereka dengan serta-merta. Ia membolehkan anda memberikan perkhidmatan yang lebih pantas kepada adat anda

Terangkan konsep pengikatan statik lewat dalam PHP. Terangkan konsep pengikatan statik lewat dalam PHP. Mar 21, 2025 pm 01:33 PM

Artikel membincangkan pengikatan statik lewat (LSB) dalam PHP, yang diperkenalkan dalam Php 5.3, yang membolehkan resolusi runtime kaedah statik memerlukan lebih banyak warisan yang fleksibel. Isu: LSB vs polimorfisme tradisional; Aplikasi Praktikal LSB dan Potensi Perfo

Pembalakan PHP: Amalan Terbaik untuk Analisis Log PHP Pembalakan PHP: Amalan Terbaik untuk Analisis Log PHP Mar 10, 2025 pm 02:32 PM

Pembalakan PHP adalah penting untuk memantau dan menyahpepijat aplikasi web, serta menangkap peristiwa kritikal, kesilapan, dan tingkah laku runtime. Ia memberikan pandangan yang berharga dalam prestasi sistem, membantu mengenal pasti isu -isu, dan menyokong penyelesaian masalah yang lebih cepat

Cara mendaftar dan menggunakan penyedia perkhidmatan Laravel Cara mendaftar dan menggunakan penyedia perkhidmatan Laravel Mar 07, 2025 am 01:18 AM

Bekas perkhidmatan dan penyedia perkhidmatan Laravel adalah asas kepada seni bina. Artikel ini meneroka bekas perkhidmatan, butiran pembekal perkhidmatan, pendaftaran, dan menunjukkan penggunaan praktikal dengan contoh. Kita akan mulakan dengan ove

See all articles