迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

PHP扩展开发 ini配置项定义

作者:迹忆客 最近更新:2021/07/02 浏览次数:

扩展 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

除非注明转载,本站文章均为原创或翻译,欢迎转载,转载请以链接形式注明出处

本文地址:

迹忆客

专注技术分享,项目实战分享!

技术宅 乐于分享 7年编程经验
社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

热门文章

教程更新

热门标签