微信号:we21cto

介绍:21CTO(21CTO.com)是中国项级技术专家的学习与服务平台.我们为CTO、技术总监、架构师等技术专家提供高质量的资讯、问答、活动等产品,同时与企业连接,提供技术咨询、研发、运维、技术支持、培训及人才招聘等服...

PHP7扩展开发之常量定义

2016-12-24 19:00 信海龙


社区导读:本文为苍老师PHP扩展开发之常量定义篇。大家都知道在PHP中如何定义常量,但是如何在PHP7.x的扩展开发中定义常量呢?看了本文,相信对想从事PHP扩展开发的同学有所助益。

前言

各位好,相信大家知道如何在PHP扩展中定义一个常量。在脚本中,定义常量的代码如下之所示:

1
2
3
4
5
6
7
8

<?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扩展中定义三个常量,上面PHP代码中的三个常量定义(const define)。基础代码

下面这个扩展,我们将在say扩展的 PHP_MINIT_FUNCTION(say) 方法上增加相应的代码。say扩展相关代码大家请看以前的文章或到博客bo56.com上查看

我们要增加的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

//增加两个方法

//释放hash

static 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文件中。想定义一个常量,很简单,只要调用对应的宏方法即可。如:

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

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

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

1
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创建一个数组。
数组创建完后,我们需要初始化。初始化的代码就是

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

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

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

1
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去释放就可以解决了。

看了以上文章,相信大家对PHP常量定义已经清晰。咱们下回开发接着谈。

 
21CTO 更多文章 Web API设计之最佳实践 深度理解HTTP与RESTFull API php-fpm解读-进程管理的三种模式 技术负责人如何做Headcount预算? 四象限管理法——时间管理
猜您喜欢 Code Review最佳实践 Go slices的用法和内部机制 与年轻电子工程师谈谈最关心的前途问题 从Trie到Double Array Trie SSD领域职位_第五期