PHP7内核(四):生命周期之开始前的躁动
上一章我们对PHP的源码目录结构有了初步了解,本章我们继续从生命周期的维度对PHP进行剖析。
一、概览
生命周期是什么呢?你可以把它看作执行过程,PHP的生命周期也就是它从开始执行到结束执行的过程。
PHP生命周期有五个阶段,分别为模块初始化阶段、请求初始化阶段、执行阶段、请求关闭阶段、模块关闭阶段。只是不同SAPI模式下,请求的情况略有不同,比如FastCGI下只经历了一次模块初始化阶段,接下来所有请求只经历请求初始化、执行脚本、请求关闭阶段。

在初步了解生命周期的五个阶段之后,我们先来讲述在进入模块初始化阶段(php_module_startup)之前PHP所做的工作(本文继续以PHP7.0.12版本的CLI模式)。好了,我们现在开始。
二、源码分析
2.1、sapi_module_struct
cli模式下的入口文件是sapi/cli/php_cli.c,打开该文件,定位到主函数main,有没有觉得1180行出现的结构体sapi_module_struct很眼熟?这就是上篇文章SAPI的介绍中提到到结构体,它是扩展PHP对外服务的关键。
//sapi/cli/php_cli.c
sapi_module_struct *sapi_module = &cli_sapi_module;
先来看一下sapi_module_struct在main/SAPI.h中的定义:
//main/SAPI.h
struct _sapi_module_struct {
char *name; //名字,如cli、fpm等
char *pretty_name; //更容易理解的名字
int (*startup)(struct _sapi_module_struct *sapi_module); //模块启动时调用的函数
int (*shutdown)(struct _sapi_module_struct *sapi_module); //模块结束时调用的函数
int (*activate)(void); //处理request时需要调用的函数
int (*deactivate)(void); //处理完request要调用的函数
size_t (*ub_write)(const char *str, size_t str_length); //用于输出数据
void (*flush)(void *server_context); //刷新缓存
zend_stat_t *(*get_stat)(void); //判断对执行的文件是否有执行权限
char *(*getenv)(char *name, size_t name_len); //获取函数变量的函数指针
void (*sapi_error)(int type, const char *error_msg, ...); //错误处理函数指针
int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); //调用header()时被调用的函数
int (*send_headers)(sapi_headers_struct *sapi_headers); //发送全部header的函数指针
void (*send_header)(sapi_header_struct *sapi_header, void *server_context); //发送某一个header的函数指针
size_t (*read_post)(char *buffer, size_t count_bytes); //获取HTTP POST中数据的函数指针
char *(*read_cookies)(void); //获取COOKIE
void (*register_server_variables)(zval *track_vars_array); //从$_SERVER中获取变量的函数指针
void (*log_message)(char *message); //输出错误信息函数指针
double (*get_request_time)(void); //获取请求时间的函数指针
void (*terminate_process)(void); //调用exit退出时的函数指针
char *php_ini_path_override; //PHP的ini文件被复写的地址
void (*block_interruptions)(void);
void (*unblock_interruptions)(void);
void (*default_post_reader)(void); //负责解析POST数据
void (*treat_data)(int arg, char *str, zval *destArray); //对数据进行处理
char *executable_location; //执行的地理位置
int php_ini_ignore; //是否不使用任何ini配置文件
int php_ini_ignore_cwd; //忽略当前路径的php.ini
int (*get_fd)(int *fd); //获取执行文件的fd的函数指针
int (*force_http_10)(void); //强制使用http1.0版本的函数指针
int (*get_target_uid)(uid_t *); //获取执行程序的uid函数指针
int (*get_target_gid)(gid_t *); //获取执行程序的gid函数指针
unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len); //对输入进行过滤的函数指针,比如将输入参数填充到自动全局变量$_GET、$_POST、$_COOKIE中
void (*ini_defaults)(HashTable *configuration_hash);
int phpinfo_as_text; //是否输出phpinfo信息 //默认的ini配置的函数指针,把ini配置信息在HashTable中
char *ini_entries; //执行时附带的ini配置,可以使php -d设置
const zend_function_entry *additional_functions; //每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title
unsigned int (*input_filter_init)(void);
}
SAPI下的每一个模式都实现了该结构体,比如在CLI中:
//sapi/cli/php_cli.c
static sapi_module_struct cli_sapi_module = {
"cli", /* name */
"Command Line Interface", /* pretty name */
......
}
FPM中:
//sapi/fpm/fpm/fpm_main.c
static sapi_module_struct cgi_sapi_module = {
"fpm-fcgi", /* name */
"FPM/FastCGI", /* pretty name */
......
}
在litespeed中也有相同定义:
//sapi/litespeed/lsapi_main.c
static sapi_module_struct lsapi_sapi_module =
{
"litespeed",
"LiteSpeed V6.10",
......
}
2.2、sapi_startup
我们继续往下看,在经过一系列变量的初始化后,于1302行又调用了sapi_startup函数。
//sapi/cli/php_cli.c
sapi_startup(sapi_module);
该函数定义了sapi_globals_struct,也就是我们常说的SG宏,它的主要作用是保存请求的基本信息,比如服务器信息、header、编码等。
//main/SAPI.h
typedef struct _sapi_globals_struct {
void *server_context;
sapi_request_info request_info;
sapi_headers_struct sapi_headers;
int64_t read_post_bytes;
unsigned char post_read;
unsigned char headers_sent;
zend_stat_t global_stat;
char *default_mimetype;
char *default_charset;
HashTable *rfc1867_uploaded_files;
zend_long post_max_size;
int options;
zend_bool sapi_started;
double global_request_time;
HashTable known_post_content_types;
zval callback_func;
zend_fcall_info_cache fci_cache;
} sapi_globals_struct;
2.3、sapi_module->startup
我们继续往下看,sapi_module调用了startup函数:
//sapi/cli/php_cli.c
if (sapi_module->startup(sapi_module) == FAILURE) {
exit_status = 1;
goto out;
}
然后又调用了CLI在sapi_module_struct中定义的startup对应的钩子函数php_cli_startup:
//sapi/cli/php_cli.c
static sapi_module_struct cli_sapi_module = {
"cli", /* name */
"Command Line Interface", /* pretty name */
php_cli_startup, /* startup */
......
}
继续跟进,php_cli_startup函数中又调用了php_module_startup函数:
//sapi/cli/php_cli.c
static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */
{
if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
return FAILURE;
}
return SUCCESS;
}
2.4、php_module_startup
是不是很眼熟,这不就是模块初始化阶段的函数嘛!原来执行了这么久才到我们的关键点,模块初始化阶段内容比较多,我们通过下一章进行详细剖析。
//main/main.c
int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
{
zend_utility_functions zuf;
zend_utility_values zuv;
int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
char *php_os;
zend_module_entry *module;
...
}
注意:我在本文贴出的代码都标识了文件位置,我们可以看出来,在PHP五大生命周期开始之前一直都是在sapi目录中执行的,而从php_module_struct也就是模块初始化阶段开始,才执行到了main目录,这意味着PHP的生命周期的第一个阶段是从main目录下开始的。
PHP7内核(四):生命周期之开始前的躁动的更多相关文章
- 跟厂长学PHP7内核(四):生命周期之开始前的躁动
上一章我们对PHP的源码目录结构有了初步了解,本章我们继续从生命周期的维度对PHP进行剖析. 一.概览 生命周期是什么呢?你可以把它看作执行过程,PHP的生命周期也就是它从开始执行到结束执行的过程. ...
- maven学习(四)maven的生命周期
官网:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html maven有三套相互独立的生命周期, ...
- 数据库设计 Step by Step (2)——数据库生命周期
引言:数据库设计 Step by Step (1)得到这么多朋友的关注着实出乎了我的意外.这也坚定了我把这一系列的博文写好的决心.近来工作上的事务比较繁重,加之我期望这个系列的文章能尽可能的系统.完整 ...
- vue笔记 - 生命周期第二次学习与理解
对于刚接触vue一两个月.才仅仅独立做过一两个vue项目的小白来说,以前一直自我感觉自己知道vue的生命周期, 直到前两天去面试,面试官让我说一下vue的生命周期... 其实我的心中是有那张图的,但是 ...
- react新的生命周期
一. react16当前生命周期 componentWillMountrender前,所以setState不会重新渲染,服务端渲染唯一调用,推荐用constructor代替之 render compo ...
- Android全面解析之Activity生命周期
前言 很高兴遇见你~ 欢迎阅读我的文章. 关于Activity生命周期的文章,网络上真的很多,有很多的博客也都讲得相当不错,可见Activity的重要性是非常高的.事实上,我猜测每个android开发 ...
- vue2和vue3生命周期的区别
概念 首先,我们了解一下"生命周期"这个词.通俗的来说,生命周期就是一个事务从出生到消失的过程.例如,一个人从出生到去世.在vue中,vue的生命周期是指,从创建vue对象到销毁v ...
- 生命周期(vue的钩子函数)
生命周期图示 创建前,创建后,挂载前,挂载后,更新前,更新后,销毁前,销毁后 beforeCreate:function(){ console.log('1-beforeCreate 组件还未被创建' ...
- vue生命周期简单总结
生命周期(钩子函数):一个组件从创建到销毁的过程就是生命周期 beforeCreate: 创建前 1.当前vue实例化的时候会做一个初始化的操作,在这个生命周期函数中我们可以做初始化的 ...
随机推荐
- string类中getline函数的应用
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- 基于activity的强大java工作流引擎,可视化开发工作流
我们先来看看工作流引擎和Activity? 工作流引擎 所谓工作流引擎是指workflow作为应用系统的一部分,并为之提供对各应用系统有决定作用的根据角色.分工和条件的不同决定信息传递路由.内容等级等 ...
- 前阿里数据库专家总结的MySQL里的各种锁(下篇)
在上篇中,我们介绍了MySQL中的全局锁和表锁. 今天,我们专注于介绍一下行锁,这个在日常开发和面试中常常困扰我们的问题. 1.行锁基础 由于全局锁和表锁对增删改查的性能都会有较大影响,所以,我们自然 ...
- 7-30 jmu-python-凯撒密码加密算法 (10 分)
编写一个凯撒密码加密程序,接收用户输入的文本和密钥k,对明文中的字母a-z和字母A-Z替换为其后第k个字母. 输入格式: 接收两行输入,第一行为待加密的明文,第二行为密钥k. 输出格式: 输出加密后的 ...
- 【转】css样式自动换行(强制换行)
原文链接:http://blog.csdn.net/ye987987... 自动换行问题,正常字符的换行是比较合理的,而连续的数字和英文字符常常将容器撑大,挺让人头疼,下面介绍的是CSS如何实现换行的 ...
- Vue进阶课堂之《从HTML到Pug》
是啥 Pug听起来或许比较陌生,但是如果说起她的前生,相信各位多少会有耳闻:Jade.每当你不停的敲打<><><><></></> ...
- flask之三:视图高级
视图高级 app.route和app.add_url_rule app.add_url_rule app.add_url_rule('/list/',endpoint='myweb',view_fun ...
- 前端H5,点击选择图片控件,图片直接在页面上展示~
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- DirectX11--深入理解Effects11、使用着色器反射机制(Shader Reflection)实现一个复杂Effects框架
前言 如果之前你是跟随本教程系列学习的话,应该能够初步了解Effects11(现FX11)的实现机制,并且可以编写一个简易的特效管理框架,但是随着特效种类的增多,要管理的着色器.资源等也随之变多.如果 ...
- vue 动态加载图片路径报错解决方法
最近遇到图片路径加载报错的问题 之前一直都是把图片放到assets的文件下的.总是报错,看到一些文章并且尝试成功了,特意记录下 首先先说明下vue-cli的assets和static的两个文件的区别, ...