struct _zend_ini_entry { int module_number; // 模块的id int modifiable; // 可被修改的范围,例如php.ini,ini_set char *name; // 配置项的名称 uint name_length; ZEND_INI_MH((*on_modify)); // 回调函数,配置项注册或修改的时候会调用 void *mh_arg1; // 通常为配置项字段在XXX_G中的偏移量 void *mh_arg2; // 通常为XXX_G void *mh_arg3; // 通常为保留字段,极少用到 char *value; // 配置项的值 uint value_length; char *orig_value; // 配置项的原始值 uint orig_value_length; int orig_modifiable; // 配置项的原始modifiable int modified; // 是否发生过修改,如果有修改,则orig_value会保存修改前的值 void (*displayer)(zend_ini_entry *ini_entry, int type); };
2.3,将配置作用到模块——REGISTER_INI_ENTRIES经常能够在不同扩展的PHP_MINIT_FUNCTION里看到REGISTER_INI_ENTRIES。REGISTER_INI_ENTRIES主要负责完成两件事情,第一,对模块的全局空间XXX_G进行填充,同步configuration_hash中的值到XXX_G中去。其次,它还生成了EG(ini_directives)。
REGISTER_INI_ENTRIES也是一个宏,展开之后实则为zend_register_ini_entries方法。具体来看下zend_register_ini_entries的实现:
ZEND_API int zend_register_ini_entries(const zend_ini_entry *ini_entry, int module_number TSRMLS_DC) /* {{{ */ { // ini_entry为zend_ini_entry类型数组,p为数组中每一项的指针 const zend_ini_entry *p = ini_entry; zend_ini_entry *hashed_ini_entry; zval default_value; // EG(ini_directives)就是registered_zend_ini_directives HashTable *directives = registered_zend_ini_directives; zend_bool config_directive_success = 0; // 还记得ini_entry最后一项固定为{ 0, 0, NULL, ... }么 while (p->name) { config_directive_success = 0; // 将p指向的zend_ini_entry加入EG(ini_directives) if (zend_hash_add(directives, p->name, p->name_length, (void*)p, sizeof(zend_ini_entry), (void **) &hashed_ini_entry) == FAILURE) { zend_unregister_ini_entries(module_number TSRMLS_CC); return FAILURE; } hashed_ini_entry->module_number = module_number; // 根据name去configuration_hash中查询,取出来的结果放在default_value中 // 注意default_value的值比较原始,一般是数字、字符串、数组等,具体取决于php.ini中的写法 if ((zend_get_configuration_directive(p->name, p->name_length, &default_value)) == SUCCESS) { // 调用on_modify更新到模块的全局空间XXX_G中 if (!hashed_ini_entry->on_modify || hashed_ini_entry->on_modify(hashed_ini_entry, Z_STRVAL(default_value), Z_STRLEN(default_value), hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC) == SUCCESS) { hashed_ini_entry->value = Z_STRVAL(default_value); hashed_ini_entry->value_length = Z_STRLEN(default_value); config_directive_success = 1; } } // 如果configuration_hash中没有找到,则采用默认值 if (!config_directive_success && hashed_ini_entry->on_modify) { hashed_ini_entry->on_modify(hashed_ini_entry, hashed_ini_entry->value, hashed_ini_entry->value_length, hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC); } p++; } return SUCCESS; }
简单来说,可以把上述代码的逻辑表述为:
1,将模块声明的ini配置项添加到EG(ini_directives)中。注意,ini配置项的值可能在随后被修改。
2,尝试去configuration_hash中寻找各个模块需要的ini。
如果能够找到,说明用户叜ini文件中配置了该值,那么采用用户的配置。
如果没有找到,OK,没有关系,因为模块在声明ini的时候,会带上默认值。