大粨兔奶糖

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

php 启动过程 - sapi MINIT 过程

sapi 概念

  • sapi 是 php 的应用编程接口, server 端接收请求通过 sapi 接口层交给 php 处理
  • 不同的 server 端底层实现不同, 相应的数据结构已经方法也有所不同, 但是对于 php 层面来说是一样的, 就是因为 sapi 层的存在
  • sapi 层对不同的 server 端进行了封装, 让 php 在处理时, 采用统一的处理方法, 并不感知底层到底是什么 server 端

sapi 生命周期前的启动过程 (以 apache2 为例)

  • apache 加载 php 模块

    • httpd.conf 配置

      • LoadModule php5_module modules/mod_php5.so
        
      • php5_module 是模块名称

      • apache 在启动加载模块时会根据模块名查找并加载模块, apache 模块文件必须是 "mod_" 开头的文件, 对于 php 来说, 则是 mod_php5.c

      • apache 的每个模块均为 module 结构体

        • AP_MODULE_DECLARE_DATA module php5_module = {
          	STANDARD20_MODULE_STUFF,
          	create_php_config,		/* create per-directory config structure */
          	merge_php_config,		/* merge per-directory config structures */
          	NULL,					/* create per-server config structure */
          	NULL,					/* merge per-server config structures */
          	// 模块指令集合
          	php_dir_cmds,			/* command apr_table_t */
          	// php 模块注册钩子, 服务启动时注册
          	php_ap2_register_hook	/* register hooks */
          };
          
        • php_dir_cmds 为模块指令集, 当 apache 接收到指令后, 会遍历每个模块的指令集, 查看哪个模块能处理该指令, 进而调用相应处理函数

        • php_ap2_register_hook 为模块注册钩子, 当 apache 启动加载模块时调用

          • void php_ap2_register_hook(apr_pool_t *p)
            {
            	ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
            	// apache2 的注册钩子
            	ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
            	// apache2 处理请求时的钩子
            	ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
            	ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
            }
            
          • 定义位置在 sapi/apache2handler/sapi_apache2.c

          • ap_hook_pre_config, ap_hook_post_config, ap_hook_child_init 这三个钩子均在 apache 启动时调用, ap_hook_handler 钩子在每次处理请求时均会调用, 在 ap_hook_post_config 中启动 php

          • 调用 php_apache_server_startup

            • static int php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
              {
              	// 省略
              	if (apache2_php_ini_path_override) {
              		apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override;
              	}
              #ifdef ZTS
              	// 启动线程安全资源管理
              	tsrm_startup(1, 1, 0, NULL);
              #endif
              	// sapi 启动
              	sapi_startup(&apache2_sapi_module);
              	// 
              	apache2_sapi_module.startup(&apache2_sapi_module);
              	apr_pool_cleanup_register(pconf, NULL, php_apache_server_shutdown, apr_pool_cleanup_null);
              	php_apache_add_version(pconf);
              
              	return OK;
              }
              
  • sapi 启动

    • sapi 模块结构体

      static sapi_module_struct apache2_sapi_module = {
      	"apache2handler",
      	"Apache 2.0 Handler",
      
      	php_apache2_startup,				/* startup */
      	php_module_shutdown_wrapper,			/* shutdown */
      
      	NULL,						/* activate */
      	NULL,						/* deactivate */
      
      	php_apache_sapi_ub_write,			/* unbuffered write */
      	php_apache_sapi_flush,				/* flush */
      	php_apache_sapi_get_stat,			/* get uid */
      	php_apache_sapi_getenv,				/* getenv */
      
      	php_error,					/* error handler */
      
      	php_apache_sapi_header_handler,			/* header handler */
      	php_apache_sapi_send_headers,			/* send headers handler */
      	NULL,						/* send header handler */
      
      	php_apache_sapi_read_post,			/* read POST data */
      	php_apache_sapi_read_cookies,			/* read Cookies */
      
      	php_apache_sapi_register_variables,
      	php_apache_sapi_log_message,			/* Log message */
      	php_apache_sapi_get_request_time,		/* Request Time */
      	NULL,						/* Child Terminate */
      
      	STANDARD_SAPI_MODULE_PROPERTIES
      };
      
    • 调用 tsrm_startup (启动线程安全资源管理, 此处不做进一步展开, 在线程安全时单独展开)

    • 调用 sapi_startup (main/SAPI.c)

      SAPI_API void sapi_startup(sapi_module_struct *sf)
      {
      #ifdef ZEND_SIGNALS
      	zend_signal_startup();
      #endif
      
      	sf->ini_entries = NULL;
      	sapi_module = *sf;
      
      #ifdef ZTS
      	ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
      # ifdef PHP_WIN32
      	_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
      # endif
      #else
      	sapi_globals_ctor(&sapi_globals);
      #endif
      
      	virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
      
      #ifdef PHP_WIN32
      	tsrm_win32_startup();
      #endif
      
      	reentrancy_startup();
      }
      
      • zend_signal_startup: 信号系统

      • sapi_globals_ctor: 创建 sapi 全局结构

        • static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
          {
          	memset(sapi_globals, 0, sizeof(*sapi_globals));
          	zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
          	php_setup_sapi_content_types(TSRMLS_C);
          }
          
        • typedef struct _sapi_globals_struct {
          	// server 环境上下文
          	void *server_context;
          	// 请求信息
          	sapi_request_info request_info;
          	// 头信息
          	sapi_headers_struct sapi_headers;
          	// post 字节数
          	int read_post_bytes;
          	// 是否发送头
          	unsigned char headers_sent;
          	struct stat global_stat;
          	// 默认 mime 类型
          	char *default_mimetype;
          	// 默认字符集
          	char *default_charset;
          	// 上传文件
          	HashTable *rfc1867_uploaded_files;
          	// post 请求最大大小
          	long post_max_size;
          	int options;
          	// sapi 是否已启动
          	zend_bool sapi_started;
          	// 请求时间
          	double global_request_time;
          	// 已知的 post 的 content_type
          	HashTable known_post_content_types;
          	zval *callback_func;
          	zend_fcall_info_cache fci_cache;
          	zend_bool callback_run;
          } sapi_globals_struct;
          
        • 调用 php_setup_sapi_contents_types, 设置 post 请求相关的参数和处理方法

          int php_setup_sapi_content_types(TSRMLS_D)
          {
          	sapi_register_post_entries(php_post_entries TSRMLS_CC);
          
          	return SUCCESS;
          }
          
          static sapi_post_entry php_post_entries[] = {
          	{ DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data,	php_std_post_handler },
          	{ MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
          	{ NULL, 0, NULL, NULL }
          };
          
          struct _sapi_post_entry {
          	char *content_type;
          	uint content_type_len;
          	void (*post_reader)(TSRMLS_D);
          	void (*post_handler)(char *content_type_dup, void *arg TSRMLS_DC);
          };
          
          • 调用 sapi_register_post_entries

            • SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
              {
              	sapi_post_entry *p=post_entries;
              
              	while (p->content_type) {
              		if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
              			return FAILURE;
              		}
              		p++;
              	}
              	return SUCCESS;
              }
              
            • SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
              {
              	// 若 sapi 已启动并且正在执行当中, 不允许注册 post 结构体
              	if (SG(sapi_started) && EG(in_execution)) {
              		return FAILURE;
              	}
              	return zend_hash_add(&SG(known_post_content_types),
              			post_entry->content_type, post_entry->content_type_len+1,
              			(void *) post_entry, sizeof(sapi_post_entry), NULL);
              }
              
    • 调用 apache2_sapi_module.startup

      static int php_apache2_startup(sapi_module_struct *sapi_module)
      {
      	if (php_module_startup(sapi_module, &php_apache_module, 1)==FAILURE) {
      		return FAILURE;
      	}
      	return SUCCESS;
      }
      
      • php_apache_module 参数是 zend 引擎封装的模块结构

        • zend_module_entry php_apache_module = {
          	STANDARD_MODULE_HEADER,
          	"apache2handler",
          	apache_functions,
          	PHP_MINIT(apache), // 扩展为 zm_startup_##module
          	PHP_MSHUTDOWN(apache), // 扩展为 zm_shutdown_##module
          	NULL,
          	NULL, 
          	PHP_MINFO(apache), // 扩展为 zm_info_##module
          	NULL,
          	STANDARD_MODULE_PROPERTIES
          };
          
        • struct _zend_module_entry {
          	unsigned short size;
          	unsigned int zend_api;
          	unsigned char zend_debug;
          	unsigned char zts;
          	const struct _zend_ini_entry *ini_entry;
          	const struct _zend_module_dep *deps;
          	// 模块名称
          	const char *name;
          	const struct _zend_function_entry *functions;
          	// 模块启动时调用的函数
          	int (*module_startup_func)(INIT_FUNC_ARGS);
          	// 模块关闭时调用的函数
          	int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
          	// 请求开始时调用的函数
          	int (*request_startup_func)(INIT_FUNC_ARGS);
          	// 请求结束时调用的函数
          	int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
          	// 模块信息函数
          	void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
          	// 版本
          	const char *version;
          	size_t globals_size;
          #ifdef ZTS
          	ts_rsrc_id* globals_id_ptr;
          #else
          	void* globals_ptr;
          #endif
          	void (*globals_ctor)(void *global TSRMLS_DC);
          	void (*globals_dtor)(void *global TSRMLS_DC);
          	int (*post_deactivate_func)(void);
          	int module_started;
          	unsigned char type;
          	void *handle;
          	int module_number;
          	const char *build_id;
          };
          
      • 调用 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;
          	
          	// 省略 ...
          
          	module_shutdown = 0;
          	module_startup = 1;
          	// 初始化空请求
          	sapi_initialize_empty_request(TSRMLS_C);
          	// sapi 激活
          	sapi_activate(TSRMLS_C);
          
          	if (module_initialized) {
          		return SUCCESS;
          	}
          
          	sapi_module = *sf;
          	// php 输出功能启动
          	php_output_startup();
          	// 设置 zend 引擎使用的函数
          	zuf.error_function = php_error_cb;
          	zuf.printf_function = php_printf;
          	zuf.write_function = php_output_wrapper;
          	zuf.fopen_function = php_fopen_wrapper_for_zend;
          	zuf.message_handler = php_message_handler_for_zend;
          	zuf.block_interruptions = sapi_module.block_interruptions;
          	zuf.unblock_interruptions = sapi_module.unblock_interruptions;
          	zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
          	zuf.ticks_function = php_run_ticks;
          	zuf.on_timeout = php_on_timeout;
          	zuf.stream_open_function = php_stream_open_for_zend;
          	zuf.vspprintf_function = vspprintf;
          	zuf.getenv_function = sapi_getenv;
          	zuf.resolve_path_function = php_resolve_path_for_zend;
          	// zend 引擎启动
          	zend_startup(&zuf, NULL TSRMLS_CC);
          
          	// 省略 ...
          	
          	// 创建垃圾回收机制全局结构体
          	gc_globals_ctor(TSRMLS_C);
          
          	// 省略 ...
          	
          	// 设置全局结构体的一些值
          	EG(bailout) = NULL;
          	EG(error_reporting) = E_ALL & ~E_NOTICE;
          	EG(active_symbol_table) = NULL;
          	PG(header_is_being_sent) = 0;
          	SG(request_info).headers_only = 0;
          	SG(request_info).argv0 = NULL;
          	SG(request_info).argc=0;
          	SG(request_info).argv=(char **)NULL;
          	PG(connection_status) = PHP_CONNECTION_NORMAL;
          	PG(during_request_startup) = 0;
          	PG(last_error_message) = NULL;
          	PG(last_error_file) = NULL;
          	PG(last_error_lineno) = 0;
          	EG(error_handling)  = EH_NORMAL;
          	EG(exception_class) = NULL;
          	PG(disable_functions) = NULL;
          	PG(disable_classes) = NULL;
          	EG(exception) = NULL;
          	EG(objects_store).object_buckets = NULL;
          
          	// 省略 ...
          	
          	// 注册一些常量
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_MINOR_VERSION", PHP_MINOR_VERSION, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_RELEASE_VERSION", PHP_RELEASE_VERSION, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTRA_VERSION", PHP_EXTRA_VERSION, sizeof(PHP_EXTRA_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_VERSION_ID", PHP_VERSION_ID, CONST_PERSISTENT | CONST_CS);
          #ifdef ZTS
          	REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 1, CONST_PERSISTENT | CONST_CS);
          #else
          	REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 0, CONST_PERSISTENT | CONST_CS);
          #endif
          	REGISTER_MAIN_LONG_CONSTANT("PHP_DEBUG", PHP_DEBUG, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_OS", php_os, strlen(php_os), CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_SAPI", sapi_module.name, strlen(sapi_module.name), CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("DEFAULT_INCLUDE_PATH", PHP_INCLUDE_PATH, sizeof(PHP_INCLUDE_PATH)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PEAR_INSTALL_DIR", PEAR_INSTALLDIR, sizeof(PEAR_INSTALLDIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PEAR_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_PREFIX", PHP_PREFIX, sizeof(PHP_PREFIX)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINDIR", PHP_BINDIR, sizeof(PHP_BINDIR)-1, CONST_PERSISTENT | CONST_CS);
          #ifndef PHP_WIN32
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_MANDIR", PHP_MANDIR, sizeof(PHP_MANDIR)-1, CONST_PERSISTENT | CONST_CS);
          #endif
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_LIBDIR", PHP_LIBDIR, sizeof(PHP_LIBDIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_DATADIR", PHP_DATADIR, sizeof(PHP_DATADIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_SYSCONFDIR", PHP_SYSCONFDIR, sizeof(PHP_SYSCONFDIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_LOCALSTATEDIR", PHP_LOCALSTATEDIR, sizeof(PHP_LOCALSTATEDIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, strlen(PHP_CONFIG_FILE_PATH), CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_MAXPATHLEN", MAXPATHLEN, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS);
          
          #ifdef PHP_WIN32
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MAJOR",      EG(windows_version_info).dwMajorVersion, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MINOR",      EG(windows_version_info).dwMinorVersion, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_BUILD",      EG(windows_version_info).dwBuildNumber, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PLATFORM",   EG(windows_version_info).dwPlatformId, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MAJOR",   EG(windows_version_info).wServicePackMajor, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MINOR",   EG(windows_version_info).wServicePackMinor, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SUITEMASK",  EG(windows_version_info).wSuiteMask, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PRODUCTTYPE", EG(windows_version_info).wProductType, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_DOMAIN_CONTROLLER", VER_NT_DOMAIN_CONTROLLER, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_SERVER", VER_NT_SERVER, CONST_PERSISTENT | CONST_CS);
          	REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_WORKSTATION", VER_NT_WORKSTATION, CONST_PERSISTENT | CONST_CS);
          #endif
          	// php 命令初始化, 主要是设置 php 命令路径
          	php_binary_init(TSRMLS_C);
          	if (PG(php_binary)) {
          		REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", PG(php_binary), strlen(PG(php_binary)), CONST_PERSISTENT | CONST_CS);
          	} else {
          		REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", "", 0, CONST_PERSISTENT | CONST_CS);
          	}
          	// 注册 php 输出功能相关的一些常量
          	php_output_register_constants(TSRMLS_C);
          	// 注册 php 上传功能相关的一些常量
          	php_rfc1867_register_constants(TSRMLS_C);
          
          	// 读取 php.ini 配置
          	if (php_init_config(TSRMLS_C) == FAILURE) {
          		return FAILURE;
          	}
          
          	// 将 php.ini 文件读取的配置注册成 ini_entry
          	REGISTER_INI_ENTRIES();
          
          	// 注册 zend 引擎的 ini_entry
          	zend_register_standard_ini_entries(TSRMLS_C);
          
          	/* Disable realpath cache if an open_basedir is set */
          	if (PG(open_basedir) && *PG(open_basedir)) {
          		CWDG(realpath_cache_size_limit) = 0;
          	}
          
          	// php 流的初始化
          	if (php_init_stream_wrappers(module_number TSRMLS_CC) == FAILURE)	{
          		php_printf("PHP:  Unable to initialize stream url wrappers.\n");
          		return FAILURE;
          	}
          
          	zuv.html_errors = 1;
          	zuv.import_use_extension = ".php";
          	// 注册超全局数组 $_GET, $_POST, $_COOKIE, ...
          	php_startup_auto_globals(TSRMLS_C);
          	zend_set_utility_values(&zuv);
          	// 启动 sapi 的处理请求功能, 设置一些处理函数
          	php_startup_sapi_content_types(TSRMLS_C);
          
          	// 注册 php 内置扩展 (module_registry)
          	if (php_register_internal_extensions_func(TSRMLS_C) == FAILURE) {
          		php_printf("Unable to start builtin modules\n");
          		return FAILURE;
          	}
          	// 注册附加扩展 (module_registry)
          	php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC);
          	// 注册 php.ini 文件设置的扩展 (zend_extensions)
          	php_ini_register_extensions(TSRMLS_C);
          
          	// 启动各模块 (module_registry), 调用各模块的 startup 方法
          	zend_startup_modules(TSRMLS_C);
          	// 启动各扩展 (zend_extentions), 调用各扩展的 startup 方法
          	zend_startup_extensions();
          	// 统计各模块的启动情况
          	zend_collect_module_handlers(TSRMLS_C);
          
          	/* register additional functions */
          	if (sapi_module.additional_functions) {
          		if (zend_hash_find(&module_registry, "standard", sizeof("standard"), (void**)&module)==SUCCESS) {
          			EG(current_module) = module;
          			zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
          			EG(current_module) = NULL;
          		}
          	}
          
          	// 禁用函数
          	php_disable_functions(TSRMLS_C);
          	// 禁用类
          	php_disable_classes(TSRMLS_C);
          
          	// 省略 ...
          
          	// sapi 
          	sapi_deactivate(TSRMLS_C);
          	module_startup = 0;
          	// 关闭内存管理
          	shutdown_memory_manager(1, 0 TSRMLS_CC);
          	zend_interned_strings_snapshot(TSRMLS_C);
          
          	/* we're done */
          	return retval;
          }
          
        • 初始化 zend 引擎使用的一些函数和值

        • 初始化 sapi_global 的一些值 (通过初始化空请求, sapi 激活)

        • 初始化全局结构体的一些值

        • zend 引擎启动

        • 设置一些常量

        • 加载 php.ini 配置

        • 注册各子模块和扩展

        • 启动各子模块和扩展

        • 禁用函数和类

    • 调用 apr_pool_cleanup_register

sapi 生命周期

  • MINIT

    若不细致区分 sapi 启动前的准备工作与启动过程, 上面的部分均可以看成是 sapi MINIT 过程
    若细致区分, sapi 启动前的准备工作是在注册 php 内置扩展之前的部分; 之后的部分为 MINIT 过程
    
  • RINIT

  • RSHUTDOWN

  • MSHUTDOWN

对于以上内容的更细致的点, 比如线程资源安全, zend 引擎启动, 全局结构体, php.ini 如何加载配置等等等等, 由于篇幅问题, 不在此赘述, 内容太多消化不了, 会在后续一个一个详细剖析, 本节仅涉及到 sapi 生命周期当中的 MINIT 过程
posted on 2017-04-06 18:02  大粨兔奶糖  阅读(306)  评论(0)    收藏  举报