php内核探索笔记-初窥

一、概括

编程语言分为两类:编译型,解释型。

编译型语言主要包括,C/C++、C#等。编译型语言有一个专门的编译过程,通过编译器编译成机器语言,只需要一次编译过程,每次执行不需要重新编译。

解释型语言主要包括,PHP,PYTHON等。编译型语言在执行前并不需要编译过程,可以直接执行,每次执行需要解释器将代码解释成机器语言(也即编译)。为了执行效率,并不是所有的语言每次执行都需要编译,例如:PHP的opcode缓存扩展(APC,xcache, eAccelerator等)。


PHP作为一种优秀的脚本语言,从简单的“hello word”到各种框架的开发、架构的设计、性能优化,以及PHP模块的开发,涉及较广知识结构和跨度。PHP通过不断淬炼,PHP内核中涉及从脚本的编译解析到执行以及和Web服务器等的配合,内存管理,语法实现等。

二、PHP执行过程

PHP的执行和其他语言一样包括,读入数据->处理->输出。PHP与C程序的最大不同,C程序是一般用来解决某个问题,而PHP实现包括了把用户逻辑翻译成机器语言来执行的功能,这也是各种编译语言与承载业务逻辑代码的最大区别。

程序的执行
1 . 如上例中, 传递给ph p程序需要执行的文件,ph p程序完成基本的准备工作后启动PHPZen d引擎, 加载注册的扩展模块。
2 . 初始化完成后读取脚本文件,Zen d引擎对脚本文件进行词法分析,语法分析。然后编译成opcode执行。 如过安装了apc之类的opcode缓存,编译环节可能会被跳过而直接从缓存中读取opcode执行。

PHP代码的执行流程,

词法分析是将PHP代码拆分成一个个”单元“(token)。PHP词法分析器通过lex生成, 词法规则文件在$PHP_SRC/ Zend/zend_ language_scanner.l 

语法分析是将token转化为Zend Engine可执行的操作。语法分析器根据语法规则进行处理,Zend Engine对代码进行编译,然后生成对应opcode;如果匹配不到语法规则,则会停止Zend Engine,然后输出错误信息。完成opcode生成后,Zend Engine会执行opcode,在执行过程会继续重复编译->执行,因为可能包含或执行其他文件或字符串的脚本。


PHP语言做为一种基于C的编程语言,在执行的过程中是如何将代码转化为机器语言的呢?


、PHP一次请求生命周期

1.SAPI

SAPI(Server Application Programming Interface)服务器具体应用编程接口,是一个通用编程接口协议,类似于PC操作系统中接口,不论是什么服务器只要满足接口标准都可以在PC上运行。PC执行方式,通过WEB服务器、命令行。

WEB服务器和命令行执行都是以SAPI接口实现开始的,只是不同SAPI接口实现不同功能。


每个SAPI实现都是通过一个sapi_module_struct结构体变量(SAPI接口),需要调用服务器相关信息时,都是通过调用该结构体对应方法,而该方法在各个服务器抽象层都有各自的实现。

cgi模式和apache2服务器为例,它们的启动方法如下:
其部分定义如下:

<span style="font-size:14px;"> cgi_sapi_module.startup(&cgi_sapi_module) // cgi模式 cgi/cgi_main.c文件

 apache2_sapi_module.startup(&apache2_sapi_module); //apache</span>
cgi_sapi_module是sapi_module_struct的静态结构体变量,startup方法指向php_cgai_startup函数指针。在该结构体中除了有startup函数指针,还有其他方法:

struct _sapi_module_struct {
 char *name; // 名字( 标识用)
 char *pretty_name; 

 int (*startup)(struct _sapi_module_struct *sapi_module); // 启动函数
 int (*shutdown)(struct _sapi_module_struct *sapi_module); // 关闭方法
 int (*activate)(TSRMLS_D); // 激活
 int (*deactivate)(TSRMLS_D); // 停用
 int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC); // 不缓存的写操作(unbuffered write)
 void (*flush)(void *server_context); // flush
 struct stat *(*get_stat)(TSRMLS_D); // get uid
 char *(*getenv)(char *name, size_t name_len TSRMLS_DC); // getenv

 void (*sapi_error)(int type, const char *error_msg, ...); /* error handler */

 int (*header_handler)(sapi_header_struct *sapi_header,sapi_header_op_enum op,
 sapi_headers_struct *sapi_headers TSRMLS_DC); /* header handler*/

 /* send headers handler */
 int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);

 void (*send_header)(sapi_header_struct *sapi_header,
 void *server_context TSRMLS_DC); /* send header handler */

 int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); /* read POST data */
 char *(*read_cookies)(TSRMLS_D); /* read Cookies */

 /* register server variables */
 void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);

 void (*log_message)(char *message); /* Log message */
 time_t (*get_request_time)(TSRMLS_D); /* Request Time */
 void (*terminate_process)(TSRMLS_D); /* Child Terminate */

 char *php_ini_path_override; // 覆盖的ini路径

 };

结构体中对应的方法在各个服务器的接口中都有实现。整个SAPI类似于OO中模板模式的应用,SAPI.c和SAPI.h中函数就是对方法的抽象,每个服务器接口的实现就是一个具体的模板。

2.

PHP执行后主要分为两个阶段:请求前开始阶段、请求后结束阶段;

请求前开始阶段分为两个过程:

模块初始化过程(MINIT),在整个SAPI生命周期只进行一次。会进行的工作:调用模块的MINIT函数、模块的初始化工作;

模块激活过程(RINIT),该过程发生在请求阶段,每次请求都会进行RINIT。请求到达后,初始化执行脚本的基本环境,例如创建一个执行环境,包括保存PHP运行过程中变量名称和值内容的符号表, 以及当前所有的函数以及类等信息的符号表;调用模块的RINIT函数。

请求结束就进入了结束阶段。与开始阶段对应,结束阶段也分为两个过程:请求结束后停用模块(RSHUTDOWN)、SAPI生命周期结束时关闭模块(MSHUTDOWN)。

3.

*单进程的SAPI生命周期:

        CLI/CGI属于单进程的SAPI,只会经过开始->请求开始->请求关闭->SAPI结束。


启动:初始化变量和全局变量、初始化Zend引擎和核心组件、解析php.ini、全局操作函数的初始化、初始化静态加载模块和共享模块(MINIT)、禁用函数和类;

ACTIVATION:除了调用模块请求初始化、激活Zend引擎、激活SAPI、环境初始化(用户空间需要用到的环境);

运行;

DEACTIVATION;

结束

*多进程SAPI生命周期


在Apache启动后会fork多个子进程,每个进程的内存空间独立。进程会经过开始和结束阶段,只在fork后进行一次开始阶段,在一个进程中可能会处理多次请求,进程结束或Apache关闭后进行结束阶段。

*多线程SAPI生命周期

在多线程中会在进程中并行的进行请求开始-请求结束阶段。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值