Table des matières
catalogue
1. SAPI接口
Relevant Link:
2. PHP CLI模式解释执行脚本流程
Copyright (c) 2016 LittleHann All rights reserved
Maison développement back-end tutoriel php PHP解释器引擎执行流程

PHP解释器引擎执行流程

Jun 23, 2016 pm 01:17 PM

catalogue

1. SAPI接口2. PHP CLI模式解释执行脚本流程3. PHP Zend Complile/Execute函数接口化(Hook Call架构基础)
Copier après la connexion

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};/* }}} */
Copier après la connexion

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

http://www.nowamagic.net/librarys/veda/detail/1285
Copier après la connexion

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;    ..
Copier après la connexion

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;}
Copier après la connexion

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();    ..
Copier après la connexion

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

PHP_MINIT_FUNCTION(extension_name){ /* Initialize functions, classes etc */ }
Copier après la connexion

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 */ }
Copier après la connexion

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);    ..
Copier après la connexion

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);        ..
Copier après la connexion

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);  
Copier après la connexion

在引擎初始化的时候,会将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词法解析过程    ..
Copier après la connexion

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);  
Copier après la connexion

在引擎初始化的时候,会将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);}
Copier après la connexion

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 */ }
Copier après la connexion

0x6: MSHUTDOWN

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

PHP_MSHUTDOWN_FUNCTION(extension_name) { /* Free handlers and persistent memory etc */ }
Copier après la connexion

/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;}
Copier après la connexion
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
Copier après la connexion

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
Copier après la connexion

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

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Travailler avec les données de session Flash dans Laravel Travailler avec les données de session Flash dans Laravel Mar 12, 2025 pm 05:08 PM

Laravel simplifie la gestion des données de session temporaires à l'aide de ses méthodes de flash intuitives. Ceci est parfait pour afficher de brefs messages, alertes ou notifications dans votre application. Les données ne persistent que pour la demande ultérieure par défaut: $ demande-

Curl dans PHP: Comment utiliser l'extension PHP Curl dans les API REST Curl dans PHP: Comment utiliser l'extension PHP Curl dans les API REST Mar 14, 2025 am 11:42 AM

L'extension PHP Client URL (CURL) est un outil puissant pour les développeurs, permettant une interaction transparente avec des serveurs distants et des API REST. En tirant parti de Libcurl, une bibliothèque de transfert de fichiers multi-protocol très respectée, PHP Curl facilite Efficient Execu

Misque de réponse HTTP simplifié dans les tests Laravel Misque de réponse HTTP simplifié dans les tests Laravel Mar 12, 2025 pm 05:09 PM

Laravel fournit une syntaxe de simulation de réponse HTTP concise, simplifiant les tests d'interaction HTTP. Cette approche réduit considérablement la redondance du code tout en rendant votre simulation de test plus intuitive. L'implémentation de base fournit une variété de raccourcis de type de réponse: Utiliser illuminate \ support \ faades \ http; Http :: faux ([[ 'google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

Découvrez les téléchargements de fichiers dans Laravel avec Storage :: Télécharger Découvrez les téléchargements de fichiers dans Laravel avec Storage :: Télécharger Mar 06, 2025 am 02:22 AM

La méthode de téléchargement du stockage :: du framework Laravel fournit une API concise pour gérer en toute sécurité les téléchargements de fichiers tout en gérant les abstractions du stockage de fichiers. Voici un exemple d'utilisation de stockage :: télécharger () dans l'exemple de contrôleur:

12 meilleurs scripts de chat PHP sur Codecanyon 12 meilleurs scripts de chat PHP sur Codecanyon Mar 13, 2025 pm 12:08 PM

Voulez-vous fournir des solutions instantanées en temps réel aux problèmes les plus pressants de vos clients? Le chat en direct vous permet d'avoir des conversations en temps réel avec les clients et de résoudre leurs problèmes instantanément. Il vous permet de fournir un service plus rapide à votre personnalité

Expliquez le concept de liaison statique tardive en PHP. Expliquez le concept de liaison statique tardive en PHP. Mar 21, 2025 pm 01:33 PM

L'article traite de la liaison statique tardive (LSB) dans PHP, introduite dans PHP 5.3, permettant une résolution d'exécution de la méthode statique nécessite un héritage plus flexible. Problème main: LSB vs polymorphisme traditionnel; Applications pratiques de LSB et perfo potentiel

PHP Logging: meilleures pratiques pour l'analyse du journal PHP PHP Logging: meilleures pratiques pour l'analyse du journal PHP Mar 10, 2025 pm 02:32 PM

La journalisation PHP est essentielle pour surveiller et déboguer les applications Web, ainsi que pour capturer des événements critiques, des erreurs et un comportement d'exécution. Il fournit des informations précieuses sur les performances du système, aide à identifier les problèmes et prend en charge le dépannage plus rapide

Comment s'inscrire et utiliser les fournisseurs de services Laravel Comment s'inscrire et utiliser les fournisseurs de services Laravel Mar 07, 2025 am 01:18 AM

Les fournisseurs de services et les fournisseurs de services de Laravel sont fondamentaux pour son architecture. Cet article explore les conteneurs de services, détaille la création du fournisseur de services, l'enregistrement et démontre l'utilisation pratique avec des exemples. Nous commencerons par un ove

See all articles