今天在开发PHP扩展中遇到了获取ini配置的需求,采用如下的方法获取发现得到的是空值:
static inline String ini_get(String varname)
{
char *value = zend_ini_string((char *) varname.c_str(), (uint)
varname.length(), 0);
if (!value)
{
return "";
}
return value;
}
在ini文件中我是这样配置的:
[catx]
catx.abc = "hello"
经过谷歌搜索,发现了 这篇博客 介绍了INI的使用方式,发现ini是需要先声明才能获取的。
通常的用法,是先通过下面的宏定义一个INI数组:
ZEND_INI_BEGIN()
ZEND_INI_ENTRY("catx.abc", "hi", PHP_INI_ALL, NULL)
ZEND_INI_END()
通过查看Zend源码,其对应展开如下:
#define ZEND_INI_BEGIN() static const zend_ini_entry_def ini_entries[] =
{
#define ZEND_INI_ENTRY(name, default_value, modifiable, on_modify) \
ZEND_INI_ENTRY_EX(name, default_value, modifiable, on_modify, NULL)
#define ZEND_INI_ENTRY_EX(name, default_value, modifiable, on_modify,
displayer) \
ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, NULL, NULL,
NULL, displayer)
#define ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify,
arg1, arg2, arg3, displayer) \
{ name, on_modify, arg1, arg2, arg3, default_value, displayer, modifiable,
sizeof(name)-1, sizeof(default_value)-1 },
#define ZEND_INI_END() { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0}
};
其实就是定义了一个zend_ini_entry_def的数组,其名字固定叫做ini_entries,里面每一项是要注册的INI配置。
上面的宏定义,无论你是在函数里还是全局作用域定义都是可以的,但是还需要主动注册到zend里去,通常用下面的2个宏来搞定:
#define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries,
module_number)
#define UNREGISTER_INI_ENTRIES()
zend_unregister_ini_entries(module_number)
上述宏默认就会找ini_entries变量传进去,第二个参数module_number你可以在扩展的MINIT和MSHUTDOWN两个函数的回调参数里得到,所以REGISTER_INI_ENTRIES要在MINIT里调用,后者在MSHUTDOWN里调用用于销毁注册的INI配置。
再就是关注一下zend_ini_entry_def的定义:
typedef struct _zend_ini_entry_def {
const char *name;
ZEND_INI_MH((*on_modify));
void *mh_arg1;
void *mh_arg2;
void *mh_arg3;
const char *value;
void (*displayer)(zend_ini_entry *ini_entry, int type);
int modifiable;
uint name_length;
uint value_length;
} zend_ini_entry_def;
name是ini配置的key,value是默认值(也就是ini里没配置时候的值),mh_arg1-3是用户可以指定的上下文参数(主要是用来displayer和on_modify回调时候提供上下文),modifiable是限制是否可以通过ini_set来修改ini配置,name_length是name的长度,value_length是value的长度。
on_modify和displayer没必要用,通过php代码ini_set修改变量可以直接反应到zend_ini_string的结果中,这些回调函数只是给你一个主动通知机制,一般是用不到的。
因为 PHP-X项目 是C++封装的Zend api,所以没法直接用上面的宏来搞定这些事情,因此需要绕过宏直接与Zend api交互:
// INI
struct IniEntry {
std::string name;
std::string default_value;
int modifiable;
};
// modifiable can be one of
these:PHP_INI_SYSTEM/PHP_INI_PERDIR/PHP_INI_USER/PHP_INI_ALL
void addIniEntry(const char* name, const char* default_value = "", int
modifiable = PHP_INI_ALL)
{
IniEntry entry;
entry.name = name;
entry.default_value = default_value;
entry.modifiable = modifiable;
ini_entries.push_back(entry);
}
protected:
std::vector ini_entries;
通过上述接口,允许用户添加若干ini配置,当MINIT回调的时候一股脑给它注册上去:
void Extension::registerIniEntries(int module_number) {
if (!ini_entries.size()) {
return;
}
zend_ini_entry_def* entry_defs = new zend_ini_entry_def[ini_entries.size()
+ 1];
for (auto i = 0; i < ini_entries.size(); ++i) {
IniEntry& entry = ini_entries[i];
zend_ini_entry_def def = {
entry.name.c_str(), // name
NULL, // on_modify
NULL, // mh_arg1
NULL, // mh_arg2
NULL, // mh_arg3
entry.default_value.c_str(), // value
NULL, // displayer
entry.modifiable, // modifiable
(uint)entry.name.size(), // name_length
(uint)entry.default_value.size(), // value_length
};
entry_defs[i] = def;
}
memset(entry_defs + ini_entries.size(), 0, sizeof(*entry_defs));
zend_register_ini_entries(entry_defs, module_number);
delete []entry_defs;
}
当MSHUTDOWN的时候一键卸载:
void Extension::unregisterIniEntries(int module_number) {
if (ini_entries.size()) {
zend_unregister_ini_entries(module_number);
}
}
这样就搞定ini了~
今天就给大家讲这么多吧,php作为开发类的一个语言,现在受到越来越多人的关注,选择合肥达内PHP培训,不再孤军奋战,轻轻松松做IT高薪白领。合肥达内培训带领有明确目标的学子迈向成功之路!
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!