php 启动过程 - sapi MINIT 过程
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 过程
php 启动过程 - sapi MINIT 过程的更多相关文章
- php 启动过程 - sapi MSHUTDOWN 过程
php 启动过程 - sapi MSHUTDOWN 过程 概述 当服务器关闭时, 会走到 sapi MSHUTDOWN 过程 注册过程 本次内容是在 php 启动过程 - sapi MINIT 过程 ...
- php 启动过程 - reqeust RINIT 过程
php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...
- php 启动过程 - reqeust RSHUTDOWN 过程
php 启动过程 - reqeust RSHUTDOWN 过程 概述 request RSHUTDOWN 过程在请求结束后调用 调用触发 同 request RINIT 过程一样, 先是用 apach ...
- SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用
目录 SpringBoot IoC启动流程.初始化过程及Bean生命周期各个阶段的作用 简述 首先明确IoC容器是啥 准备-SpringApplication的实例化 启动-SpringApplica ...
- 第三次作业(1) Visual Studio程序安装过程和练习过程
Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...
- Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向
Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向 1. 一个伟大的事业必然是过程导向为主 1 1.1. 过程的执行情况(有明确的执行手册及标准) ...
- VScript 函数调用的两种分类:Sub过程和Function过程
来源:http://soft.zdnet.com.cn/software_zone/2007/0925/523318.shtml 在 VBScript 中,过程被分为两类:Sub 过程和 Functi ...
- Oracle数据库体系结构、启动过程、关闭过程
一.Oracle数据库体系结构体系结构由下面组件组成:1.Oracle服务器(Server):由数据库实例和数据库文件组成,另外在用户建立与服务器的连接时启动服务器进程并分配PGA(程序全局区) (1 ...
- iOS开发实践:一个类微博客户端从启动到与用户交互的过程
本文基于数据字典和数据流图两种工具讲述一个完整微博客户端的实现.数据字典和数据流图都可以用来表达线程的执行流程,同时定义了需要的类,是进一步设计类的基础. 数据字典实际上是一张表,表的第一个字段是程序 ...
随机推荐
- 徒手用Java来写个Web服务器和框架吧<第一章:NIO篇>
因为有个不会存在大量连接的小的Web服务器需求,不至于用上重量级服务器,于是自己动手写一个服务器. 同时也提供了一个简单的Web框架.能够简单的使用了. 大体的需求包括 能够处理HTTP协议. 能够提 ...
- thinkphp apicloud 下拉刷新 。。。由于新人里面导入了vue.js
//刷新 apiready = function(){ var count; var i= 1; var param = {}; toDoRequest(); param.loadingImgae = ...
- jQuery后续...
jQuery 选择器 1.jQuery选择器的简介 (1). Jquery中的选择器完全继承了CSS的风格,利用Jquery选择器,可以非常便捷和快速的找出特定的Dom元素,然后为他们添加相应的行为, ...
- macOS apache配置及开启虚拟服务器的开启,apache开启重写模式
今天把自己的mac系统升到最新版,但是,apache却不能用了,因为mac上的apache是系统自带的,因为是mac目前的最新系统,所以出现了好多问题,整理了一下午也没有啥进展,最后还是把原来的在云盘 ...
- MSTP多实例的配置
MSTP多实例的配置 这次实验主要是为了加强对stp生成树协议中,RP(根端口),DP(指定端口),AP(阻塞端口)的判断方法:虽然很多时候不需要我们人工判断,因为当我们吧所有的配置好之后,然后开启生 ...
- [读书系列] 深度探索C++对象模型 初读
2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...
- TypeScript设计模式之中介者、观察者
看看用TypeScript怎样实现常见的设计模式,顺便复习一下. 学模式最重要的不是记UML,而是知道什么模式可以解决什么样的问题,在做项目时碰到问题可以想到用哪个模式可以解决,UML忘了可以查,思想 ...
- mybatis基础学习4-插件生成器
1:安装 2:在所建项目单击右键输入mybatis如下图 *建项目文件时不用建包和类,在配置文件里写即可生成 3:之后在项目生成 自己建的表(这个必须) 单击右键 即可 --------------- ...
- Java中反射与常用方法
java通常是先有类再有对象,有对象我就可以调用方法或者属性. 反射其实是通过Class对象来调用类里面的方法.通过反射可以调用私有方法和私有属性.大部分框架都是运用反射原理. 如何获得Class ...
- centos7 安装kubernetes1.4
192.168.251.9 master192.168.251.231 node 建议可以搭建etcd集群来做数据库存储,并搭建kube-dns,然后把k8s的日志落地到/var/log/kubern ...