PHP内核源码阅读过程(六)

本文详细解析了PHP内核启动时的关键步骤,包括初始化全局变量、扩展注册、数据处理函数注册、内部及额外模块的启动等。通过SG和EG了解sapi_globals和executor_globals结构,探讨了php扩展与zend扩展的区别,并提到了禁用函数和类的配置选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

一、php_startup_auto_globals 初始化常用的全局变量

void php_startup_auto_globals(void)
{
	zend_register_auto_global(zend_string_init_interned("_GET", sizeof("_GET")-1, 1), 0, php_auto_globals_create_get);
	zend_register_auto_global(zend_string_init_interned("_POST", sizeof("_POST")-1, 1), 0, php_auto_globals_create_post);
	zend_register_auto_global(zend_string_init_interned("_COOKIE", sizeof("_COOKIE")-1, 1), 0, php_auto_globals_create_cookie);
	zend_register_auto_global(zend_string_init_interned("_SERVER", sizeof("_SERVER")-1, 1), PG(auto_globals_jit), php_auto_globals_create_server);
	zend_register_auto_global(zend_string_init_interned("_ENV", sizeof("_ENV")-1, 1), PG(auto_globals_jit), php_auto_globals_create_env);
	zend_register_auto_global(zend_string_init_interned("_REQUEST", sizeof("_REQUEST")-1, 1), PG(auto_globals_jit), php_auto_globals_create_request);
	zend_register_auto_global(zend_string_init_interned("_FILES", sizeof("_FILES")-1, 1), 0, php_auto_globals_create_files);
}

二、zend_set_utility_values 保存支持的扩展

	zuv.html_errors = 1;
	zuv.import_use_extension = ".php";
	zuv.import_use_extension_length = (uint32_t)strlen(zuv.import_use_extension);

void zend_set_utility_values(zend_utility_values *utility_values)
{
	zend_uv = *utility_values;
	zend_uv.import_use_extension_length = (uint32_t)strlen(zend_uv.import_use_extension);
}

三、php_startup_sapi_content_types 注册几个数据处理函数

1. 读取post数据的函数

SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(void))
{
	if (SG(sapi_started) && EG(current_execute_data)) {
		return FAILURE;
	}
	sapi_module.default_post_reader = default_post_reader;
	return SUCCESS;
}

sapi_register_default_post_reader(php_default_post_reader);

2. 处理数据的函数

SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray))
{
	if (SG(sapi_started) && EG(current_execute_data)) {
		return FAILURE;
	}
	sapi_module.treat_data = treat_data;
	return SUCCESS;
}

sapi_register_treat_data(php_default_treat_data);

3. 过滤函数

SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len), unsigned int (*input_filter_init)(void))
{
	if (SG(sapi_started) && EG(current_execute_data)) {
		return FAILURE;
	}
	sapi_module.input_filter = input_filter;
	sapi_module.input_filter_init = input_filter_init;
	return SUCCESS;
}

sapi_register_input_filter(php_default_input_filter, NULL);

这里的SG和EG分辨是sapi_globals和executor_globals全局结构

# define SG(v) (sapi_globals.v)
# define EG(v) (executor_globals.v)

四、php_register_internal_extensions_func 内部扩展注册

这是一个函数指针,其赋值位于main/main.c

PHPAPI int (*php_register_internal_extensions_func)(void) = php_register_internal_extensions;

内部模块列表:

static zend_module_entry * const php_builtin_extensions[] = {
	phpext_standard_ptr
#if HAVE_BCMATH
	,phpext_bcmath_ptr
#endif
#if HAVE_CALENDAR
	,phpext_calendar_ptr
#endif
	,phpext_com_dotnet_ptr
#if HAVE_CTYPE
	,phpext_ctype_ptr
#endif
#if HAVE_DATE
	,phpext_date_ptr
#endif
#if HAVE_FTP
	,phpext_ftp_ptr
#endif
#if HAVE_HASH
	,phpext_hash_ptr
#endif
#if HAVE_ICONV
	,phpext_iconv_ptr
#endif
#if HAVE_MBSTRING
	,phpext_mbstring_ptr
#endif
#if HAVE_UODBC
	,phpext_odbc_ptr
#endif
#if HAVE_PCRE || HAVE_BUNDLED_PCRE
	,phpext_pcre_ptr
#endif
	,phpext_reflection_ptr
#if HAVE_PHP_SESSION
	,phpext_session_ptr
#endif
#if HAVE_TOKENIZER
	,phpext_tokenizer_ptr
#endif
#if HAVE_ZLIB
	,phpext_zlib_ptr
#endif
#if HAVE_LIBXML
	,phpext_libxml_ptr
#if HAVE_DOM
	,phpext_dom_ptr
#endif
#if HAVE_SIMPLEXML
	,phpext_simplexml_ptr
#endif
#endif
#if HAVE_XML
	,phpext_xml_ptr
#endif
#if HAVE_XML && HAVE_WDDX
	,phpext_wddx_ptr
#endif
#if HAVE_SPL
	,phpext_spl_ptr
#endif
#if HAVE_XML && HAVE_XMLREADER
	,phpext_xmlreader_ptr
#endif
#if HAVE_XML && HAVE_XMLWRITER
	,phpext_xmlwriter_ptr
#endif
};

除了第一个模块phpext_standard_ptr, 其他模块的启用都需要在执行configure的时候设置对应的参数,否则不会启用。这些模块都是静态编译,所以不需要写到ini文件里。关于模块的详细分析,这个之后再讲。

五、php_register_extensions_bc 注册额外的PHP模块

在cli模式下,这个是空的

如果是fpm模式下,会有一个额外的模块注册 cgi_module_entry

static const zend_function_entry cgi_fcgi_sapi_functions[] = {
	PHP_FE(fastcgi_finish_request,                    cgi_fcgi_sapi_no_arginfo)
	PHP_FE(fpm_get_status,                            cgi_fcgi_sapi_no_arginfo)
	PHP_FE(apache_request_headers,                    cgi_fcgi_sapi_no_arginfo)
	PHP_FALIAS(getallheaders, apache_request_headers, cgi_fcgi_sapi_no_arginfo)
	PHP_FE_END
};

static zend_module_entry cgi_module_entry = {
	STANDARD_MODULE_HEADER,
	"cgi-fcgi",
	cgi_fcgi_sapi_functions,
	PHP_MINIT(cgi),
	PHP_MSHUTDOWN(cgi),
	NULL,
	NULL,
	PHP_MINFO(cgi),
	NO_VERSION_YET,
	STANDARD_MODULE_PROPERTIES
};

也即多了几个跟请求相关的函数

六、php_ini_register_extensions 注册写于ini的扩展(包括Zend和PHP)

七、zend_startup_modules 启动PHP扩展

主要就是调用每个扩展的PHP_MINIT

八、zend_startup_extensions 启动Zend扩展

主要就是调用每个扩展的startup

关于php扩展和zend扩展这里特别说明一下,在内部,php扩展叫模块(module),zend扩展叫扩展(extension)

九、zend_collect_module_handlers 收集各个模块有效的PHP_RINIT, PHP_RSHUTDOWN和post_RSHUTDOWN以及类的静态成员,以便清理是调用

十、将额外的函数注册到标准扩展中(此扩展包含了绝大数php内置函数)

	if (sapi_module.additional_functions) {
		if ((module = zend_hash_str_find_ptr(&module_registry, "standard", sizeof("standard")-1)) != NULL) {
			EG(current_module) = module;
			zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT);
			EG(current_module) = NULL;
		}
	}

在cli模式下有三个函数

static const zend_function_entry additional_functions[] = {
	ZEND_FE(dl, arginfo_dl)
	PHP_FE(cli_set_process_title,        arginfo_cli_set_process_title)
	PHP_FE(cli_get_process_title,        arginfo_cli_get_process_title)
	PHP_FE_END
};

在fpm模式下,这个为空

cgi_sapi_module.additional_functions = NULL;

十一、禁用通过ini配置的函数和类

	php_disable_functions();
	php_disable_classes();

禁用函数的ini选项是 disable_functions

禁用类的ini选项是 disable_classes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值