PHP的构成及生命周期

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. 核心目录分析

  1. sapi目录:PHP的应用接口层,作为PHP的宿主环境,负责适配不同应用场景(如命令行、Web环境等),核心功能是完成PHP框架的初始化。常用的SAPI包括Cli(命令行模式)和Fpm(FastCGI进程管理器模式),代码位于/sapi目录下。

  2. main目录:存放PHP的主要代码,核心职责涵盖输入/输出处理、Web通信、PHP框架初始化等关键操作,例如fastcgi协议解析、扩展加载、PHP配置解析等工作均在此完成。

  3. Zend目录:PHP解析器(ZendVM)的核心实现目录,ZendVM是PHP语言的核心,负责PHP代码的解释与执行,等同于Java中的JVM。

  4. ext目录:PHP的扩展目录,包含各类实用扩展,如curl扩展、gd库扩展、pdo扩展等,PHP的众多功能函数均通过扩展提供。

  5. TSRM目录:线程安全相关的实现目录,保障PHP在多线程环境下的稳定运行。

3.核心组件说明

  1. SAPI(Server API)

    • PHP作为脚本解析器,需适配命令行、Web环境、嵌入式应用等不同场景,SAPI层便是适配这些环境的核心组件,可视为PHP的宿主环境。

    • 作为PHP框架最外层的一部分,SAPI主要负责PHP框架的初始化,不同SAPI实现会影响PHP生命周期各阶段的执行逻辑。

  2. ZendVM(Zend Virtual Machine)

    • 介于PHP应用与实际计算机之间的虚拟计算机,是PHP代码解释执行的核心。

    • 由编译器和执行器两部分组成:编译器负责将PHP代码转换为执行器可识别的指令,执行器负责执行这些指令。

  3. Extension(扩展)

    • 扩充PHP功能的核心方式,PHP社区提供了丰富的扩展资源,支持通过C/C++实现高性能、强功能的特性。

    • 分为PHP扩展和Zend扩展:PHP扩展为常规功能扩展,应用广泛;Zend扩展主要面向ZendVM,如知名的Opcache便是Zend扩展。

PHP的生命周期

PHP的整个生命周期划分为5个核心阶段,不同SAPI(如Cli、Fpm)的实现会导致各阶段执行情况存在差异。

1. 模块初始化阶段(module startup)

  1. 执行时机:仅在SAPI启动时执行一次(如Fpm的master进程启动时)。

  2. 入口函数:php_module_startup()

  3. 核心操作:

    • 激活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)

  1. 执行时机:每个请求处理前都会执行(如Fpm的worker进程接收请求后)。

  2. 入口函数:php_request_startup()

  3. 核心操作:

    • 激活输出: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)

  1. 执行时机:请求初始化完成后,是PHP生命周期的核心阶段。

  2. 入口函数:php_execute_script()

  3. 核心操作:

    • 编译过程:通过zend_compile_file()完成词法分析(zendlex())、语法分析,将PHP源代码转化为抽象语法树,最终生成Zend引擎可识别的opline指令。

    • 执行过程:通过zend_execute()执行opline指令,这是ZendVM的执行入口,完成PHP代码的实际运行。

4. 请求关闭阶段(request shutdown)

  1. 执行时机:脚本执行完成后。

  2. 核心操作:

    • 回调注册的钩子函数: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)

  1. 执行时机:SAPI关闭时执行一次(如Fpm停止时)。

  2. 入口函数:php_module_shutdown()

  3. 核心操作:

    • 注销扩展函数:清理扩展注册的各类函数。

    • 清理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关闭时才执行模块关闭阶段。