大家都知道PHP脚本在执行的时候用户全局变量(在用户空间显式定义的变量)会保存在一个HashTable数据类型的符号表(symbol_table)中, 在PHP中有一些比较特殊的全局变量例如: $_GET,$_POST,$_SERVER等变量,我们并没有在程序中定义这些变量,并且这些变量也同样保存在符号表中, 从这些表象我们不难得出结论:PHP是在脚本运行之前就将这些特殊的变量加入到了符号表中了。
$GLOBALS的初始化
我们以cgi模式为例说明$GLOBALS的初始化。 从cgi_main.c文件main函数开始。 整个调用顺序如下所示:
[main() -> php_request_startup() -> zend_activate() -> init_executor() ]
02 | zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0); |
07 | Z_SET_REFCOUNT_P(globals, 1); |
08 | Z_SET_ISREF_P(globals); |
09 | Z_TYPE_P(globals) = IS_ARRAY; |
10 | Z_ARRVAL_P(globals) = &EG(symbol_table); |
11 | zend_hash_update(&EG(symbol_table), "GLOBALS" , sizeof ( "GLOBALS" ), |
12 | &globals, sizeof (zval *), NULL); |
上面的代码的关键点zend_hash_update函数的调用,它将变量名为GLOBALS的变量注册到EG(symbol_table)中, EG(symbol_table)是一个HashTable的结构,用来存放所有的全局变量。 这在下面将要提到的$_GET等变量初始化时也会用到。
$_GET、$_POST等变量的初始化
$_GET、$_COOKIE、$_SERVER、$_ENV、$_FILES、$_REQUEST这六个变量都是通过如下的调用序列进行初始化。 [main() -> php_request_startup() -> php_hash_environment() ]
在请求初始化时,通过调用 php_hash_environment 函数初始化以上的六个预定义的变量。 如下所示为php_hash_environment函数的代码。在代码之后我们以$_POST为例说明整个初始化的过程。
003 | int php_hash_environment(TSRMLS_D) |
006 | unsigned char _gpc_flags[5] = {0, 0, 0, 0, 0}; |
007 | zend_bool jit_initialization = (PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays)); |
008 | struct auto_global_record { |
013 | zend_bool jit_initialization; |
014 | } auto_global_records[] = { |
015 | { "_POST" , sizeof ( "_POST" ), "HTTP_POST_VARS" , sizeof ( "HTTP_POST_VARS" ), 0 }, |
016 | { "_GET" , sizeof ( "_GET" ), "HTTP_GET_VARS" , sizeof ( "HTTP_GET_VARS" ), 0 }, |
017 | { "_COOKIE" , sizeof ( "_COOKIE" ), "HTTP_COOKIE_VARS" , sizeof ( "HTTP_COOKIE_VARS" ), 0 }, |
018 | { "_SERVER" , sizeof ( "_SERVER" ), "HTTP_SERVER_VARS" , sizeof ( "HTTP_SERVER_VARS" ), 1 }, |
019 | { "_ENV" , sizeof ( "_ENV" ), "HTTP_ENV_VARS" , sizeof ( "HTTP_ENV_VARS" ), 1 }, |
020 | { "_FILES" , sizeof ( "_FILES" ), "HTTP_POST_FILES" , sizeof ( "HTTP_POST_FILES" ), 0 }, |
022 | size_t num_track_vars = sizeof (auto_global_records)/ sizeof ( struct auto_global_record); |
026 | for (i=0; i< num_track_vars; i++) { |
027 | PG(http_globals)[i] = NULL; |
030 | for (p=PG(variables_order); p && *p; p++) { |
034 | if (!_gpc_flags[0] && !SG(headers_sent) && SG(request_info).request_method && !strcasecmp(SG(request_info).request_method, "POST" )) { |
035 | sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC); |
037 | if (PG(register_globals)) { |
038 | php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]) TSRMLS_CC); |
044 | if (!_gpc_flags[1]) { |
045 | sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC); |
047 | if (PG(register_globals)) { |
048 | php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) TSRMLS_CC); |
054 | if (!_gpc_flags[2]) { |
055 | sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC); |
057 | if (PG(register_globals)) { |
058 | php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC); |
064 | if (!jit_initialization && !_gpc_flags[3]) { |
065 | zend_auto_global_disable_jit( "_ENV" , sizeof ( "_ENV" )-1 TSRMLS_CC); |
066 | php_auto_globals_create_env( "_ENV" , sizeof ( "_ENV" )-1 TSRMLS_CC); |
068 | if (PG(register_globals)) { |
069 | php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV]) TSRMLS_CC); |
075 | if (!jit_initialization && !_gpc_flags[4]) { |
076 | zend_auto_global_disable_jit( "_SERVER" , sizeof ( "_SERVER" )-1 TSRMLS_CC); |
077 | php_register_server_variables(TSRMLS_C); |
079 | if (PG(register_globals)) { |
080 | php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]) TSRMLS_CC); |
088 | if (PG(register_argc_argv)) { |
089 | php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC); |
092 | for (i=0; i < num_track_vars; i++) { |
093 | if (jit_initialization && auto_global_records[i].jit_initialization) { |
096 | if (!PG(http_globals)[i]) { |
097 | ALLOC_ZVAL(PG(http_globals)[i]); |
098 | array_init(PG(http_globals)[i]); |
099 | INIT_PZVAL(PG(http_globals)[i]); |
102 | Z_ADDREF_P(PG(http_globals)[i]); |
103 | zend_hash_update(&EG(symbol_table), auto_global_records[i].name, auto_global_records[i].name_len, &PG(http_globals)[i], sizeof (zval *), NULL); |
104 | if (PG(register_long_arrays)) { |
105 | zend_hash_update(&EG(symbol_table), auto_global_records[i].long_name, auto_global_records[i].long_name_len, &PG(http_globals)[i], sizeof (zval *), NULL); |
106 | Z_ADDREF_P(PG(http_globals)[i]); |
111 | if (!jit_initialization) { |
112 | zend_auto_global_disable_jit( "_REQUEST" , sizeof ( "_REQUEST" )-1 TSRMLS_CC); |
113 | php_auto_globals_create_request( "_REQUEST" , sizeof ( "_REQUEST" )-1 TSRMLS_CC); |
以$_POST为例,首先以 auto_global_record 数组形式定义好将要初始化的变量的相关信息。 在变量初始化完成后,按照PG(variables_order)指定的顺序(在php.ini中指定),通过调用sapi_module.treat_data处理数据。
从PHP实现的架构设计看,treat_data函数在SAPI目录下不同的服务器应该有不同的实现,只是现在大部分都是使用的默认实现。
在treat_data后,如果打开了PG(register_globals),则会调用php_autoglobal_merge将相关变量的值写到符号表。
以上的所有数据处理是一个赋值前的初始化行为。在此之后,通过遍历之前定义的结构体, 调用zend_hash_update,将相关变量的值赋值给&EG(symbol_table)。 另外对于$_REQUEST有独立的处理方法。
没有帐号? 现在注册.