PHP的构成
1. 目录结构
PHP源码的核心目录包括:.git、appveyor、azure、build、docs、ext、main、pear、sapi、scripts、tests、travis、TSRM、win32、Zend
注:PHP源代码下载:https://github.com/php/php-src.git
2. 核心目录分析
-
sapi目录:PHP的应用接口层,作为PHP的宿主环境,负责适配不同应用场景(如命令行、Web环境等),核心功能是完成PHP框架的初始化。常用的SAPI包括Cli(命令行模式)和Fpm(FastCGI进程管理器模式),代码位于
/sapi目录下。 -
main目录:存放PHP的主要代码,核心职责涵盖输入/输出处理、Web通信、PHP框架初始化等关键操作,例如fastcgi协议解析、扩展加载、PHP配置解析等工作均在此完成。
-
Zend目录:PHP解析器(ZendVM)的核心实现目录,ZendVM是PHP语言的核心,负责PHP代码的解释与执行,等同于Java中的JVM。
-
ext目录:PHP的扩展目录,包含各类实用扩展,如curl扩展、gd库扩展、pdo扩展等,PHP的众多功能函数均通过扩展提供。
-
TSRM目录:线程安全相关的实现目录,保障PHP在多线程环境下的稳定运行。
3.核心组件说明
-
SAPI(Server API)
-
PHP作为脚本解析器,需适配命令行、Web环境、嵌入式应用等不同场景,SAPI层便是适配这些环境的核心组件,可视为PHP的宿主环境。
-
作为PHP框架最外层的一部分,SAPI主要负责PHP框架的初始化,不同SAPI实现会影响PHP生命周期各阶段的执行逻辑。
-
-
ZendVM(Zend Virtual Machine)
-
介于PHP应用与实际计算机之间的虚拟计算机,是PHP代码解释执行的核心。
-
由编译器和执行器两部分组成:编译器负责将PHP代码转换为执行器可识别的指令,执行器负责执行这些指令。
-
-
Extension(扩展)
-
扩充PHP功能的核心方式,PHP社区提供了丰富的扩展资源,支持通过C/C++实现高性能、强功能的特性。
-
分为PHP扩展和Zend扩展:PHP扩展为常规功能扩展,应用广泛;Zend扩展主要面向ZendVM,如知名的Opcache便是Zend扩展。
-
PHP的生命周期
PHP的整个生命周期划分为5个核心阶段,不同SAPI(如Cli、Fpm)的实现会导致各阶段执行情况存在差异。
1. 模块初始化阶段(module startup)
-
执行时机:仅在SAPI启动时执行一次(如Fpm的master进程启动时)。
-
入口函数:
php_module_startup()。 -
核心操作:
-
激活SAPI:
sapi_activate(),初始化请求信息SG(request_info)、设置POST请求读取句柄等。 -
启动PHP输出:
php_output_startup()。 -
初始化垃圾回收器:
gc_globals_ctor(),分配zend_gc_globals内存。 -
启动Zend引擎:
zend_startup(),包括启动内存池、设置工具函数句柄、分配符号表(函数、类、常量)、注册Zend核心扩展及标准常量、注册超全局变量获取句柄、分配php.ini配置存储符号表等。 -
注册PHP定义的常量:如PHP_VERSION、PHP_ZTS、PHP_SAPI等。
-
解析php.ini配置:结果存储在configuration_hash哈希表中,并映射到EG(ini_directives)哈希表。
-
注册静态编译扩展:
php_register_internal_extensions_func()。 -
注册动态加载扩展:
php_init_register_extensions(),加载php.ini中配置的.so动态扩展。 -
回调各扩展的module startup钩子函数(PHP_MINIT_FUNCTION定义)。
-
注册php.ini中禁用的函数和类(disable_functions、disable_classes)。
-
2. 请求初始化阶段(request startup)
-
执行时机:每个请求处理前都会执行(如Fpm的worker进程接收请求后)。
-
入口函数:
php_request_startup()。 -
核心操作:
-
激活输出:
php_output_activate()。 -
激活Zend引擎:
zend_activate(),包括重置垃圾回收器(gc_reset())、初始化编译器(init_compiler())、初始化执行器、初始化全局变量符号表(EG(symbol_table))、初始化已包含文件符号表(EG(included_files))。 -
激活SAPI:
sapi_activate(),初始化词法分析器(startup_scanner())。 -
回调各扩展的request startup钩子函数(
zend_activate_modules())。
-
3. 脚本执行阶段(execute script)
-
执行时机:请求初始化完成后,是PHP生命周期的核心阶段。
-
入口函数:
php_execute_script()。 -
核心操作:
-
编译过程:通过
zend_compile_file()完成词法分析(zendlex())、语法分析,将PHP源代码转化为抽象语法树,最终生成Zend引擎可识别的opline指令。 -
执行过程:通过
zend_execute()执行opline指令,这是ZendVM的执行入口,完成PHP代码的实际运行。
-
4. 请求关闭阶段(request shutdown)
-
执行时机:脚本执行完成后。
-
核心操作:
-
回调注册的钩子函数:
php_call_shutdown_functions(),执行通过register_shutdown_function注册的函数。 -
清理析构资源:
zend_call_destructors(),清理EG(symbol_table),调用变量析构函数(如文件句柄、socket连接等资源的释放)。 -
输出处理:
php_output_discard_all()、php_output_end_all(),关闭输出,发送HTTP应答header头,清理output handlers。 -
关闭Zend引擎相关组件:
zend_post_deactivate_modules(),调用各扩展的post_deactivate_func(多数扩展无此钩子);shutdown_scanner()关闭词法分析器。 -
销毁全局变量:
PG(http_globals)。 -
关闭内存管理器:
shutdown_memory_manager()。 -
刷新输出:
sapi_flush()。
-
5. 模块关闭阶段(module shutdown)
-
执行时机:SAPI关闭时执行一次(如Fpm停止时)。
-
入口函数:
php_module_shutdown()。 -
核心操作:
-
注销扩展函数:清理扩展注册的各类函数。
-
清理ini配置:
UNREGISTER_INI_ENTRIES(),清理ini HashTable元素。 -
关闭输出:
php_output_shutdown()。 -
清理模块资源:
zend_destroy_modules(),清理module_registry HashTable;zend_shutdown()清理持久化列表等。 -
销毁全局资源:
cre_globals_dtor()。
-
6. 不同SAPI的生命周期差异
-
Cli模式:每次执行脚本都会完整经历“模块初始化→请求初始化→脚本执行→请求关闭→模块关闭”5个阶段。
-
FastCgi(Fpm)模式:SAPI启动时执行一次模块初始化;后续每个请求仅经历“请求初始化→脚本执行→请求关闭”阶段;SAPI关闭时才执行模块关闭阶段。


