// p表示core_globals的地址加上log_errors字段的偏移量
// 得到的即为log_errors字段的地址
p = (zend_bool *) (base+(size_t) mh_arg1);
if (new_value_length == 2 && strcasecmp("on", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 3 && strcasecmp("yes", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 4 && strcasecmp("true", new_value) == 0) {
*p = (zend_bool) 1;
}
else {
// configuration_hash中存放的value是字符串"1",而非"On"
// 因此这里用atoi转化成数字1
*p = (zend_bool) atoi(new_value);
}
return SUCCESS;
}
最令人费解的估计就是mh_arg1和mh_arg2了,其实对照前面所述的zend_ini_entry定义,mh_arg1,mh_arg2还是很容易参透的。mh_arg1表示字节偏移量,mh_arg2表示XXX_globals的地址。因此,(char *)mh_arg2 + mh_arg1的结果即为XXX_globals中某个字段的地址。具体到本case中,就是计算core_globals中log_errors的地址。因此,当OnUpdateBool最后执行到
复制代码 代码如下:
*p = (zend_bool) atoi(new_value);
其作用就相当于
复制代码 代码如下:
core_globals.log_errors = (zend_bool) atoi("1");
分析完了OnUpdateBool,我们再来看OnUpdateLong便觉得一目了然:
复制代码 代码如下:
ZEND_API ZEND_INI_MH(OnUpdateLong)
{
long *p;
char *base = (char *) mh_arg2;
// 获得log_errors_max_len的地址
p = (long *) (base+(size_t) mh_arg1);
// 将"1024"转化成long型,并赋值给core_globals.log_errors_max_len
*p = zend_atol(new_value, new_value_length);
return SUCCESS;
}
最后需要注意的是,zend_register_ini_entries函数中,如果configuration_hash中存在配置,则当调用on_modify结束后,hashed_ini_entry中的value和value_length会被更新。也就是说,如果用户在php.ini中配置过,则EG(ini_directives)存放的就是实际配置的值。如果用户没配,EG(ini_directives)中存放的是声明zend_ini_entry时给出的默认值。
zend_register_ini_entries中的default_value变量命名比较糟糕,相当容易造成误解。其实default_value并非表示默认值,而是表示用户实际配置的值。
3,总结
至此,三块数据configuration_hash,EG(ini_directives)以及PG、BG、PCRE_G、JSON_G、XXX_G...已经都交代清楚了。
总结一下:
1,configuration_hash,存放php.ini文件里的配置,不做校验,其值为字符串。
2,EG(ini_directives),存放的是各个模块中定义的zend_ini_entry,如果用户在php.ini配置过(configuration_hash中存在),则值被替换为configuration_hash中的值,类型依然是字符串。
3,XXX_G,该宏用于访问模块的全局空间,这块内存空间可用来存放ini配置,并通过on_modify指定的函数进行更新,其数据类型由XXX_G中的字段声明来决定。
您可能感兴趣的文章: