php一切的开始sapi,脚本的执行都是以sapi接口实现的,apache mod_php 、php cli都是一样只是通过不通的sapi接口。
顺便提下zend虚拟机的三个部分:语法实现(词法分析、语法分析)、opcode编译、执行引擎
php的生命周期:MINIT(模块初始化调取各个扩展对应的minit,初始化zend引擎及核心组件包括对词法分析、语法分析、中间代码执行指针初始化等,全局变量及若干常量,解析php.ini文件,php_startup_auto_globals函数会初始化$_POST/$_GET等全局变量,加载内置模块包括一些使用频繁的字符串或数组函数,session等模块,同时添加进module_registry列表中)->RINIT(请求初始化包括从服务器获取一些请求数据如cookie、post数据,再通过遍历module_registry列表调用各个扩展的rinit方法)->运行(php_execute_script函数包含了运⾏PHP脚本的全部过程:当一个PHP文件需要解析执行时,它可能会需要执行三个文件,其中包括一个前置执行文件、当前需要执行的主文件和一个后置执行文件。 非当前的两个文件件可以在php.ini文件件通过auto_prepend_file参数和auto_append_file参数设置。 如果将这两个参数设置为空,则禁用对应的执行文件。对于需要解析执行的文件,通过zend_compile_file(compile_file函数)做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码。 如果解析的文件有生成有效的中间代码,则调用zend_execute(execute函数)执行中间代码。 如果在执行过程中出现异常并且用户有定义对这些异常的处理,则调用这些异常处理函数。 在所有的操作都处理完后,PHP通过EG(return_value_ptr_ptr)返回结果)->RSHUTDOWN->MSHUTDOWN(PHP关闭请求的过程是一个若干个关闭操作的集合,这个集合存在于php_request_shutdown函数中。
这个集合包括如下内容:
1. 调用所有通过register_shutdown_function()注册的函数。这些在关闭时调用的函数是在用户空间添加进来的。 一个简单的例子,我们可以在脚本出错时调用一个统一的函数,给用户一个友好些的页面,这个有点类似于网页中的404页面。2. 执行所有可用的__destruct函数。 这里的析构函数包括在对象池(EG(objects_store)中的所有对象的析构函数以及EG(symbol_table)中各个元素的析构方法。3. 将所有的输出刷出去。4. 发送HTTP应答头。这也是一个输出字符串的过程,只是这个字符串可能符合某些规范。5. 遍历每个模块的关闭请求方法,执行模块的请求关闭操作,这就是我们在图中看到的Call eachextension's RSHUTDOWN。6. 销毁全局变量表(PG(http_globals))的变量。7. 通过zend_deactivate函数,关闭词法分析器、语法分析器和中间代码执行器。8. 调用每个扩展的post-RSHUTDOWN函数。只是基本每个扩展的post_deactivate_func函数指针都是NULL。9. 关闭SAPI,通过sapi_deactivate销毁SG(sapi_headers)、SG(request_info)等的内容。10. 关闭流的包装器、关闭流的过滤器。11. 关闭内存管理。12. 重新设置最大执行时间结束最终到了要收尾的地方了。flushsapi_flush将最后的内容刷新出去。其调用的是sapi_module.flush,在CLI模式下等价于fflush函数。关闭Zend引擎zend_shutdown将关闭Zend引擎。此时对应图中的流程,我们应该是执行每个模块的关闭模块操作。 在这里只有一个zend_hash_graceful_reverse_destroy函数将module_registry销毁了。 当然,它最终也是调用了关闭模块的方法的,其根源在于在初始化module_registry时就设置了这个hash表析构时调用ZEND_MODULE_DTOR宏。 ZEND_MODULE_DTOR宏对应的是module_destructor函数。 在此函数中会调用模块的module_shutdown_func方法,即PHP_RSHUTDOWN_FUNCTION宏产生的那个函数。在关闭所有的模块后,PHP继续销毁全局函数表,销毁全局类表、销售全局变量表等。 通过zend_shutdown_extensions遍历zend_extensions所有元素,调用每个扩展的shutdown函数。)