PHP7扩展开发之常量定义

来源:互联网 发布:复旦大数据学院专业 编辑:程序博客网 时间:2024/06/11 02:31

前言

这次,我们将演示如何在PHP扩展中定义一个常量。要实现的PHP代码如下:

<?php    define("__ARR__", array('2', 'site'=>"www.bo56.com"));      define("__SITE__", "www.bo56.com", true);    define("say\__SITE__", "bo56.com");    var_dump(__ARR__);    var_dump(__site__);    var_dump(say\__SITE__);?>

我们将演示在PHP扩展中定义三个常量。如上面代码中的三个define。

代码

基础代码

这个扩展,我们将在say扩展的 PHP_MINIT_FUNCTION(say) 方法上增加相应的代码。say扩展相关代码大家请看这篇博文。PHP7扩展开发之hello word 文中已经详细介绍了如何创建一个扩展和提供了源码下载。

增加的代码如下

//增加两个方法//释放hashstatic void say_hash_destroy(HashTable *ht)    zend_string *key;    zval *element;    if (((ht)->u.flags & HASH_FLAG_INITIALIZED)) {        ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, element) {            if (key) {                free(key);            }            switch (Z_TYPE_P(element)) {                case IS_STRING:                    free(Z_PTR_P(element));                    break;                case IS_ARRAY:                    say_hash_destroy(Z_ARRVAL_P(element));                    break;            }        } ZEND_HASH_FOREACH_END();        free(HT_GET_DATA_ADDR(ht));    }       free(ht);}//释放数组和字符串static void say_entry_dtor_persistent(zval *zvalue)    if (Z_TYPE_P(zvalue) == IS_ARRAY) {        say_hash_destroy(Z_ARRVAL_P(zvalue));    } else if (Z_TYPE_P(zvalue) == IS_STRING) {        zend_string_release(Z_STR_P(zvalue));    }}//PHP_MINIT_FUNCTION(say)方法的PHP扩展源码: 扩展初始化的调用此方法PHP_MINIT_FUNCTION(say){    zend_constant c;    zend_string *key;    zval value;    ZVAL_NEW_PERSISTENT_ARR(&c.value);    zend_hash_init(Z_ARRVAL(c.value), 0, NULL,                        (dtor_func_t)say_entry_dtor_persistent, 1);    add_index_long(&c.value, 0, 2);    key = zend_string_init("site", 4, 1);    ZVAL_STR(&value, zend_string_init("www.bo56.com", 12, 1));    zend_hash_update(Z_ARRVAL(c.value), key, &value);    c.flags = CONST_CS|CONST_PERSISTENT;    c.name = zend_string_init("__ARR__", 7, 1);    c.module_number = module_number;    zend_register_constant(&c);    REGISTER_STRINGL_CONSTANT("__SITE__", "www.bo56.com", 12, CONST_PERSISTENT);    REGISTER_NS_STRINGL_CONSTANT("say", "__SITE__", "bo56.com", 8, CONST_CS|CONST_PERSISTENT);}//扩展卸载的时候调用此方法PHP_MSHUTDOWN_FUNCTION(say){    zval *val;    val = zend_get_constant_str("__ARR__", 7);    say_hash_destroy(Z_ARRVAL_P(val));    ZVAL_NULL(val);    return SUCCESS;}

代码说明

一般情况下,在扩展中只建议定义null,bool,long,double,string几种类型的常量。因为内核只提供了这几种类型的宏方法。
常量定义的宏方法在Zend/zend_constants.h文件中。想定义一个常量,很简单,只要调用对应的宏方法即可。如:

REGISTER_STRINGL_CONSTANT("__SITE__", "www.bo56.com", 12, CONST_PERSISTENT);

宏方法的最后一个参数是一些标识符。
CONST_PERSISTENT 表示为持久的。常驻内存。
CONST_CS 表示为区分大小写。
注意我们上面定义常量时使用的是SITE,但是调用的时候使用的是site

还有一套可以指定命名空间的宏方法。宏方法中带NS。如:

REGISTER_NS_STRINGL_CONSTANT("say", "__SITE__", "bo56.com", 8, CONST_CS|CONST_PERSISTENT);

第一个参数就是命名空间。

为了展示常量定义的一些细节。我们定义了一个__ARR__常量。
ZVAL_NEW_PERSISTENT_ARR(&c.value);我们想让__ARR__为持久的。所以使用ZVAL_NEW_PERSISTENT_ARR创建一个数组。
数组创建完后,我们需要初始化。初始化的代码就是

zend_hash_init(Z_ARRVAL(c.value), 0, NULL,                        (dtor_func_t)say_entry_dtor_persistent, 1);

参数中的say_entry_dtor_persistent是一个析构函数,用于释放数组的元素。

到这里,如果编译运行。当程序执行结束的时候,你会发现一个致命错误。错误信息如下:

Fatal error: Internal zval's can't be arrays, objects or resources in Unknown on line 0

因为在程序执行完毕,内部zval释放的时候,会进行类型检测。如果发现是array object或者resources,则会报错。可以查看Zend/zend_variables.c文件中_zval_internal_dtor方法。
为了解决这个问题,我们需要手动释放我们创建的__ARR__相关的数组。
模块卸载时执行的方法,是优先Zend内部zval释放方法之前调用的。因此,我们只要在PHP_MSHUTDOWN_FUNCTION(say)方法中手动释放。不再让Zend去释放就可以解决了。

源码下载

tar.gz格式下载
zip格式下载

原文链接:php7扩展开发之常量定义

0 0
原创粉丝点击