3,将ini的值同步到XX_G里面。毕竟在php的执行过程中,起作用的还是这些XXX_globals。具体的过程是调用每条ini配置对应的on_modify方法完成,on_modify由模块在声明ini的时候进行指定。
我们来具体看下on_modify,它其实是一个函数指针,来看两个具体的Core模块的配置声明:
STD_PHP_INI_BOOLEAN("log_errors", "0", PHP_INI_ALL, OnUpdateBool, log_errors, php_core_globals, core_globals) STD_PHP_INI_ENTRY("log_errors_max_len","1024", PHP_INI_ALL, OnUpdateLong, log_errors_max_len, php_core_globals, core_globals)
对于log_errors,它的on_modify被设置为OnUpdateBool,对于log_errors_max_len,则on_modify被设置为OnUpdateLong。
进一步假设我们在php.ini中的配置为:
log_errors = On log_errors_max_len = 1024
具体来看下OnUpdateBool函数:
ZEND_API ZEND_INI_MH(OnUpdateBool) { zend_bool *p; // base表示core_globals的地址 char *base = (char *) mh_arg2; // 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; }