PHP程序的执行流程

Web环境我们假设为Apache。在编译PHP的时候,为了能够让Apache支持PHP,我们会生成一个mod_php5.so的模块。 Apache加载这个模块,在url访问.php文件的时候,就会转给mod_php5.so模块来处理。这个就是我们常说的SAPI。英文名字 是:Server Application Programming Interface。SAPI其实是一个统称,其下有 ISAPI,CLI SAPI,CGI等。有了它,就可以很容易的跟其他东西交互,比如APACHE,IIS,CGI等。

Apache启动后会将mod_pho5.so模块的hook handler注册进来,当Apache检测到访问的url是一个php文件时,这时候就会把控制权交给SAPI。进入到SAPI后,首先会执行 sapi/apache/mod_php5.c 文件的php_init_handler函数,这里摘录一段代码:

static
void php_init_handler(server_rec *s, pool *p)

{

    
register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);

    
if
(!apache_php_initialized) {

        
apache_php_initialized = 1;

        
#ifdef ZTS

        
tsrm_startup(1, 1, 0, NULL);

        
#
endif

        
sapi_startup(&apache_sapi_module);

        
php_apache_startup(&apache_sapi_module);

    
}

    
#
if
MODULE_MAGIC_NUMBER >= 19980527

    
{

        
TSRMLS_FETCH();

        
if
(PG(expose_php)) {

            
ap_add_version_component(
"PHP/"
PHP_VERSION);

        
}

    
}

    
#
endif

}

该函数主要调用两个函数:sapi_startup(&apache_sapi_module); php_apache_startup(&apache_sapi_module);

SAPI_API void sapi_startup(sapi_module_struct *sf)

{

    
sf->ini_entries = NULL;

    
sapi_module = *sf;

    
.................

    
sapi_globals_ctor(&sapi_globals);

    
................

    
virtual_cwd_startup();
/* Could use shutdown to free the main cwd but it would just slow it down for CGI */

    
..................

    
reentrancy_startup();

}

sapi_startup创建一个 sapi_globals_struct结构体。sapi_globals_struct保存了Apache请求的基本信息,如服务器信 息,Header,编码等。sapi_startup执行完毕后再执行php_apache_startup。

static
int php_apache_startup(sapi_module_struct *sapi_module)

{

    
if
(php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {

        
return
FAILURE;

    
}
else
{

        
return
SUCCESS;

    
}

}

php_module_startup 内容太多,这里介绍一下大致的作用:

1. 初始化zend_utility_functions 结构.这个结构是设置zend的函数指针,比如错误处理函数,输出函数,流操作函数等.

2. 设置环境变量.

3. 加载php.ini配置.

4. 加载php内置扩展.

5. 写日志.

6. 注册php内部函数集.

7. 调用 php_ini_register_extensions,加载所有外部扩展

8. 开启所有扩展

9. 一些清理操作.

重点说一下 3,4,7,8

加载php.ini配置

if
(php_init_config(TSRMLS_C) == FAILURE) {

    
return
FAILURE;

}

php_init_config函数会在这里检查所有php.ini配置,并且找到所有加载的模块,添加到php_extension_lists结构中。

加载php内置扩展

调用 zend_register_standard_ini_entries加载所有php的内置扩展,如array,mysql等。

调用 php_ini_register_extensions,加载所有外部扩展

main/php_ini.c

void php_ini_register_extensions(TSRMLS_D)

{

    
zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);

    
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);

    
zend_llist_destroy(&extension_lists.engine);

    
zend_llist_destroy(&extension_lists.functions);

}

zend_llist_apply函数遍历extension_lists 执行会掉函数 php_load_php_extension_cb

php_load_php_extension_cb

static
void php_load_zend_extension_cb(void *arg TSRMLS_DC)

{

    
zend_load_extension(*((char **) arg));

}

该函数最后调用

if
((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) {

    
DL_UNLOAD(handle);

    
return
FAILURE;

}

将扩展信息放到 Hash表module_registry中,Zend/zend_API.c

if
(zend_hash_add(&module_registry, lcname, name_len+1, (void *)module, sizeof(zend_module_entry), (void**)&module_ptr)==FAILURE) {

    
zend_error(E_CORE_WARNING,
"Module \‘%s\‘ already loaded"
, module->name);

    
efree(lcname);

    
return
NULL;

}

最后,zend_startup_modules(TSRMLS_C); 对模块进行排序,并检测是否注册到module_registry HASH表里。zend_startup_extensions(); 执行extension->startup(extension);启动扩展。

时间: 2024-08-28 14:31:30

PHP程序的执行流程的相关文章

深入跟踪MFC程序的执行流程

来源: http://blog.csdn.net/ljianhui/article/details/8781991 在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于程序的一切细节都没有控制权的感觉.这种感觉来源于学习者不知道一个MFC程序是如何运行起来的(即一个MFC程序的执行流程)和MFC程序的设计思想和机制,即使是写过Windows程序的学习者,也会感到非常迷惘并且无从下手.而这种感觉的出现会使大家认为自己离开了书本上的例子就无法设计编制程序.下面我就来说

TXT编写程序-编译-执行流程

DOS下  1切换到程序路径Test.java这 2.javac  Test.java    >>>>>得到  .class 文件 3.java  Test             >>>>>得到 Test.java文件的输出结果 原文地址:https://www.cnblogs.com/2016-cxp/p/8654775.html

MFC 程序入口和执行流程

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

【转载】MFC 程序入口和执行流程

原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来

【转】MFC 程序入口和执行流程

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

wget www.baidu.com执行流程分析

通过GDB分析程序的执行流程如下: main.c(main) url_parse:解析url,获取url相关信息,返回结构体 struct url 的指针,存于 url_parsed retrieve_url:主要参数 url_parsed ,下载文件,下载网页的关键函数 retr.c(retrieve_url) http_loop,通过 HTTP 下载指定文件 http.c(http_loop) gethttp, 获取文档 http.c(gethttp) connect_to_host:给定域

java程序的执行

Java平台和语言最开始只是SUN公司在1990年12月开始研究的一个内部项目.SUN公司的一个叫做帕特里克·诺顿的工程师被自己开发的C和C语言编译器搞得焦头烂额,因为其中的API极其难用.帕特里克决定改用NeXT,同时他也获得了研究公司的一个叫做"Stealth 计划"的项目的机会. ??"Stealth 计划"后来改名为"Green计划",JGosling(詹姆斯·高斯林)和麦克·舍林丹也加入了帕特里克的工作小组.他们和其他几个工程师一起在加

程序执行流程(粗略)

程序执行流程(粗略) 用户发出请求 前台进行js规则验证(良好的用户体验) 按照一定的规则进行数据提交 (数据没有封装的提交 和 数据封装过后的提交) 控制层进行数据的接收 1.进行数据的非空.规则验证 || 规则验证可以读取配置文件 2.处理session信息 3.进行权限的验证 || 可以使用权限拦截器或过滤器 # 分清数据来源::: 来源于用户输入(输入数据 ), 来源于系统生成(当前时间) , 默认值在业务层之中设置保证业务的可移植性 # 在调用业务之前一定要保证将业务需要的信息已经进行

<01>主函数分析+创建一个新的Target+C语言程序执行流程

1.C语言的源程序的后缀:.c格式 2.C语言源程序: 1)由函数构成 2)在一个程序中,只有一个主函数(主函数由系统调用) 3)函数只有被调用的时候,才执行 4)如果没有主函数程序无法运行 5) C语言中语句结束一定要有分号 3.主函数的写法: int main(){ printf("hello world"); return 0; } 4.C语言程序的执行 1)command+r 2)点击左上角的 三角 符号 //Program ended with exit code: 0  程