文档章节

PHP程序的执行流程

大圈
 大圈
发布于 2015/08/25 15:54
字数 676
阅读 20
收藏 1

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);启动扩展。

本文转载自:http://blogread.cn/it/article/5524?f=wb

共有 人打赏支持
大圈
粉丝 4
博文 57
码字总数 21291
作品 0
朝阳
系统管理员
私信 提问
PHP中include()与require()的区别说明

require 的使用方法如 require("MyRequireFile.php"); 。这个函数通常放在 PHP 程序的最前面,PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部份。常用...

xinson
2014/11/06
0
0
一般用什么方式实现从PHP调用需要root权限的程序?

最近开始学习PHP,想给一个运行在后台的程序做一个Web界面。想实现的大概为这样一个流程: 1.从浏览器访问PHP(Linux,Apache服务器) 2.PHP调用system,exec等来执行服务器上的程序(c语言程序) ...

ZhuCheng
2011/01/03
1K
3
include require在php中的区别

1、include在引入不存文件时产生一个警告且脚本还会继续执行, require则会导致一个致命性错误且脚本停止执行。 2、include()是有条件包含函数,而 require()则是无条件包含函数。 3、inclu...

小神威
2016/01/08
8
0
swoole实现数据库连接池

原生 PHP CURD 让我们来回顾一下PHP中数据库的使用 上述代码, 本身是没有任何问题。这里我们也不是来挑出问题的,只是以一位多年PHPer的经验与大家交流下。 上面程序执行过程是什么样子的呢?...

太阳黑子
2016/10/28
23
0
php 任务调度框架--Task-Schedule-PHP

task-schedule-php task-schedule-php是一个php任务调度框架,开发者可以使用这个框架来设置周期任务/一次性的延时任务后期异步执行。 动机: 异步/不阻塞:用户操作的时候,服务器端除了和用...

wsdfbb2004
2016/05/30
2.5K
1

没有更多内容

加载失败,请刷新页面

加载更多

Windows同步对象Event和Linux的条件变量

最近在看一些同步对象模拟的东东,特别对在Windows下如何模拟条件变量折腾了很久。 1 Windows同步对象Event 微软有一个很有意思的同步对象,某种程度上和Linux的条件变量很相似。但秉承微软一...

shzwork
17分钟前
1
0
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

//第一种做法 public class Solution { public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) { ArrayList <Integer> li=new ArrayList<Integer>(); ArrayList <TreeN......

南桥北木
27分钟前
1
0
linux 服务管理 Crontba、Ntpdate、Logrotate、Supervisor

crond linux 系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的。 另外, 由于使用者自己也可以设置计划任务,所以,...

狼王黄师傅
57分钟前
3
0
Sobel算子和Scharr滤波器

Sobel算子在数学上的本质是微分,对离散信号,是求邻域内的增量。 基本原理:在图像上,对图像信号在某点进行微分,表示图像的某个特征(如,强度、色调或者饱和度)在该点的变换程度。以强度...

yepanl
今天
2
0
Jenkins API 使用

Jenkins 是一款流行的开源持续集成工具,可以用来做一些软件开发的自动化工作,如打包,测试,自动部署等。 Jenkins 中有 view 和 job 的概念, view 相当于组, job 则是具体的任务。 view...

YanWen
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部