PHP7扩展开发之常量定义

前言

这次,我们将演示如何在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 文中已经详细介绍了如何创建一个扩展和提供了源码下载。

增加的代码如下

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

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

更多函数说明请查看

时间: 2024-05-11 10:41:12

PHP7扩展开发之常量定义的相关文章

PHP7扩展开发之字符串处理

PHP7扩展开发之字符串处理 前言 这次,我们来看看字符串在PHP扩展里面如何处理. 示例代码如下: <?php function str_concat($prefix, $string) { $len = strlen($prefix); $substr = substr($string, 0, $len); if ($substr != $prefix) { return $prefix." ".$string; } else { return $string; } } ec

PHP7扩展开发之类型处理

前言 这次,我们将演示如何在PHP扩展中如何对类型进行一些操作.如,判断变量类型.要实现的PHP代码如下: <?php function get_size ($value) { if (is_string($value)) { return "string size is ". strlen($value); } else if (is_array($value)) { return "array size is ". sizeof($value); } el

PHP7扩展开发之数组处理

前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理.要实现的PHP代码如下: <?php function array_concat ($arr, $prefix) { foreach($arr as $key => $val) { if (isset($prefix[$key]) && is_string($val) && is_string($prefix[$key])) { $arr[$key] = $prefix[$key].$val; } }

PHP7扩展开发之创建变量

前言 在这篇博文中我们将演示如何在PHP扩展中创建一个变量.示例代码如下: <?php class demo {} $lng = 2; $str = "abc"; $arr = array(1,'a' => 'b'); $obj = new demo(); var_dump($str); var_dump($arr); var_dump($obj); ?> 中间的三行我们将用PHP扩展来实现. 代码 基础代码 这个扩展,我们将在say扩展上增加 define_var

PHP7扩展开发之传参与返回值

前言 这次,我们将演示如何在PHP扩展中接受传入的参数和输出返回值. <?php function default_value ($type, $value = null) { if ($type == "int") { return $value ?? 0; } else if ($type == "bool") { return $value ?? false; } else if ($type == "str") { return i

白话PHP7扩展开发之创建对象

本篇文章主要将如何在扩展中创建一个对象.创建的对象的过程,其实和一个小孩出生,成长的过程有些类似. 第一步,办准生证 生孩子第一步,先办准生证.声明我要生孩子了.对象创建的时候,如何办准生证呢?只要定义一个zend_class_entry变量即可.代码如下: zend_class_entry ce; zend_class_entry 是啥?可以认为它使一个原型,定义了一些对象应该有哪些东西组成.具体代码可以查看./Zend/zend.h文件. 第二步,取名字 孩子怎么得有个名字,对象也一样.如何

PHP扩展开发教程(总结)_php实例

PHP是一种解释型的语言,对于用户而言,我们精心的控制内存意味着easier prototyping和更少的崩溃!当我们深入到内核之后,所有的安全防线都已经被越过,最终还是要依赖于真正有责任心的软件工程师来保证系统的稳定运行. 1.线程安全宏定义 在TSRM/TSRM.h文件中有如下定义 #define TSRMLS_FETCH()       void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL) #define TSRMLS_FETCH_FR

PHP扩展开发入门教程

 这篇文章主要介绍了PHP扩展开发入门教程,本文讲解了使用C语言在Linux系统下开发一个PHP扩展应该具备的最基本知识,需要的朋友可以参考下     PHP扩展开发 我准备在此系列博文中总结我有关PHP扩展开发的学习和感悟,力图简单清晰地描述在Linux系统下开发一个PHP扩展应该具备的最基本知识.水平较低,难免有错误,望指出. 准备工作 首先要获取一份PHP源码(可以从Github上签出,或者到官网上下载最新的稳定版),然后编译之.为了加快编译速度,我们推荐禁用所有额外的扩展(使用--dis

Firefox(火狐)浏览器扩展开发初探

        最近开发一个FF的扩展,自动完成公司的订餐操作,主要完成的功能很简单:登陆网站,执行一个特定操作,并在ff的状态栏内显示执行的成功或者失败的状态.以前没有写过FF扩展,需要从头学习,在完成这个扩展过程中,有些收获记录下来,一方面自己记录,另一方面也方便有此需求的同学.在整个开发过程中碰到一些问题,也走了一些弯路,希望对其他同学有所帮助.         由于是第一开发FF扩展,没什么经验,所以,第一步先去搜索些关于FF插件开发的文档.先几乎把所有关于FF插件开发的中文文档看个边,