PHP扩展开发 ini配置项定义
扩展 jlog
首先、在 php_jlog.h
文件中添加如下代码。使用扩展工具生成的扩展框架中包含下面的代码,只是默认情况下是注释的,可以把注释打开然后修改。
ZEND_BEGIN_MODULE_GLOBALS(jlog)
zend_bool enable_thread;
ZEND_END_MODULE_GLOBALS(jlog)
然后、在jlog.c
文件中添加如下代码。
ZEND_DECLARE_MODULE_GLOBALS(jlog);
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("jlog.enable_thread", "1", PHP_INI_SYSTEM, OnUpdateBool, enable_thread, zend_jlog_globals, jlog_globals)
PHP_INI_END()
PHP_GINIT_FUNCTION(jlog)
{
JLOG_G(enable_thread) = 1;
}
最后需要在PHP_MINIT_FUNCTION(jlog)
中注册全局变量
PHP_MINIT_FUNCTION(jlog)
{
REGISTER_INI_ENTRIES(); // 注册全局变量入口
server_start = 0;
if(!queue_init()) {
php_error(E_ERROR,"队列初始化失败\n");
}
return SUCCESS;
}
// 在生命周期最后销毁这些全局变量
PHP_MSHUTDOWN_FUNCTION(jlog)
{
UNREGISTER_INI_ENTRIES(); // 销毁
if(server_start == 1) {
server_start = 0;
if(JLOG_G(enable_thread)) {
while (!checkQueueEmpty() || !idle) {}
pthread_cancel(tid);
pthread_join(tid, NULL);
}
}
free(jlog_queue);
return SUCCESS;
}
到此,基本流程就完成了。但是我们注意到在上面新增了PHP_GINIT_FUNCTION(jlog)
。 这是用来初始化全局变量的。但是默认情况下这是不会执行的。需要我们来手动指定其调用。
在jlog.c
默认的有个变量
zend_module_entry pen_module_entry = {
STANDARD_MODULE_HEADER,
"pen",
pen_functions,
PHP_MINIT(pen),
PHP_MSHUTDOWN(pen),
PHP_RINIT(pen), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(pen), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(pen),
PHP_PEN_VERSION,
STANDARD_MODULE_PROPERTIES
};
我们需要对这个变量的值进行修改,因为STANDARD_MODULE_PROPERTIES
宏定义如下
#define STANDARD_MODULE_PROPERTIES \
NO_MODULE_GLOBALS, NULL, STANDARD_MODULE_PROPERTIES_EX
// 其中有个宏 NO_MODULE_GLOBALS 由名字就可以知道禁止了全局变量
#define NO_MODULE_GLOBALS 0, NULL, NULL, NULL
所以我们需要将jlog.c
中的变量进行修改
zend_module_entry jlog_module_entry = {
STANDARD_MODULE_HEADER,
"jlog",
jlog_functions,
PHP_MINIT(jlog),
PHP_MSHUTDOWN(jlog),
PHP_RINIT(jlog), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(jlog), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(jlog),
PHP_JLOG_VERSION,
PHP_MODULE_GLOBALS(jlog),
PHP_GINIT(jlog), // PHP_GINIT_FUNCTION(jlog) 的调用
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
上面的变量是由zend_module_entry
定义,而zend_module_entry
结构体如下
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
unsigned short size;
unsigned int zend_api;
unsigned char zend_debug;
unsigned char zts;
const struct _zend_ini_entry *ini_entry;
const struct _zend_module_dep *deps;
const char *name;
const struct _zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
int (*request_startup_func)(INIT_FUNC_ARGS);
int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
const char *version;
size_t globals_size;
#ifdef ZTS
ts_rsrc_id* globals_id_ptr;
#else
void* globals_ptr;
#endif
void (*globals_ctor)(void *global TSRMLS_DC);
void (*globals_dtor)(void *global TSRMLS_DC);
int (*post_deactivate_func)(void);
int module_started;
unsigned char type;
void *handle;
int module_number;
const char *build_id;
};
这里定义了一个php
扩展模块的入口,里面定义了一个模块整个生命周期所需要的信息。
到此为止,已经是一个完整的扩展了。但是,还有一个问题,这个扩展只是对于ZTS版本的php有效。对于NTS版本的在编译的时候会报错。原因就是下面这段代码
PHP_GINIT_FUNCTION(jlog)
{
JLOG_G(enable_thread) = 1;
}
按照php_jlog.h 中定义的
#ifdef ZTS
#define JLOG_G(v) TSRMG(jlog_globals_id, zend_jlog_globals *, v)
extern int jlog_globals_id;
#else
#define JLOG_G(v) (jlog_globals.v)
extern zend_jlog_globals jlog_globals;
#endif
在NTS版本中,JLOG_G(v)
的定义是jlog_globals.v
。 在PHP_GINIT_FUNXTION(jlog)
函数中直接使用宏JLOG_G(enable_thread)
在编译过程中是有问题的。此时的jlog_globals
是一个指针变量,所以 jlog_globals.v 是会报错的。因此将PHP_GINIT_FUNCTION(jlog)
修改如下
PHP_GINIT_FUNCTION(jlog)
{
jlog_globals->enable_thread = 1;
}
则编译的时候则不会报错。
至于为什么NTS版本会出现这种情况,现在还没有找到具体原因,等后续研究找到原因后再回来补上,先做个TODO
相关文章
如何使用 CLion 开发调试 PHP 扩展
发布时间:2021/07/02 浏览次数:231 分类:PHP
-
php 扩展的创建这里就不再赘述,使用ext_skel 生成一个框架,然后编辑相应的文件,编译安装,最后在php.ini 配置文件中加入生成的扩展 例如 my_ext.so
PHP扩展开发之最详细的RETURN_STRINGL讲解
发布时间:2021/06/15 浏览次数:182 分类:PHP
-
本篇主要介绍在PHP扩展开发的过程中肯定会用到的一个宏 RETURN_STRINGL 。
PHP内核开发,接收用户传入的参数
发布时间:2021/06/10 浏览次数:207 分类:PHP
-
在内核开发中,在接收用户传入的参数的过程中,可以使用 zend_parse_parameters()函数。