前言
这次,我们将演示如何在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扩展中定义三个常量。如上面代码中的三个define。
代码
基础代码
这个扩展,我们将在say扩展的 PHP_MINIT_FUNCTION(say)
方法上增加相应的代码。say扩展相关代码大家请看这篇博文。PHP7扩展开发之hello word 文中已经详细介绍了如何创建一个扩展和提供了源码下载。
增加的代码如下
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去释放就可以解决了。
源码下载
文章推荐
交流社区
技术交流

原文链接:PHP7扩展开发之常量定义,转载请注明来源!
学习到了的东西!谢谢分享了
这个写的蛮好的!支持一下
感谢分享 祝您开心快乐每一天! 欢迎回访:www.qhdown.cn
博主,源代码下载不了呢