日期:2014-05-16  浏览次数:20541 次

php扩展与嵌入--资源数据类型2
在资源变量中存储的复杂的数据类型通常在初始化时需要一些内存分配,CPU时间或网络通信。但是在请求之间保留类似于数据库连接这种资源,必须要做到持久。资源是否持久是一个必须要考虑到的因素。

首先看内存分配的问题:
   
     在使用php的时候,偏向使用emalloc因为它是malloc的带回收的版本。但是持久化的资源必须在请求间都存在。对于一个文件句柄类的资源来说,如果要加入一个存储文件名的需求,那么必须在头文件中加入如下的代码:
typedef struct _php_sample_descriptor_data {
    char *filename;
    FILE *fp;
} php_sample_descriptor_data;
    利用这个结构可以存储文件名和文件句柄资源,从而能够在不同的请求之间进行共享。

   对应的,要在源文件中进行相应的更改:
static void php_sample_descriptor_dtor( //这个是进行资源回收的回调函数,定义在资源的初始化处。
                    zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
    php_sample_descriptor_data *fdata =
                (php_sample_descriptor_data*)rsrc->ptr;
    fclose(fdata->fp);
    efree(fdata->filename);
    efree(fdata);
}
    这个静态函数用来进行资源的回收,需要在初始化资源的时候进行指定回调。

    进行修改后的文件打开函数,需要增加给资源分配空间的操作:
PHP_FUNCTION(sample_fopen) //修改后的fopen
{
    php_sample_descriptor_data *fdata;
    FILE *fp;
    char *filename, *mode;
    int filename_len, mode_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
                        &filename, &filename_len,
                        &mode, &mode_len) == FAILURE) {// 获取文件名和文件长度 
        RETURN_NULL();
    }
    if (!filename_len || !mode_len) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                "Invalid filename or mode length");
        RETURN_FALSE;
    }
    fp = fopen(filename, mode);
    if (!fp) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                "Unable to open %s using mode %s",
                filename, mode);
        RETURN_FALSE;
    }
    fdata = emalloc(sizeof(php_sample_descriptor_data)); //给包含了文件资源和文件名的结构分配空间
    fdata->fp = fp;
    fdata->filename = estrndup(filename, filename_len);
    ZEND_REGISTER_RESOURCE(return_value, fdata,
                                le_sample_descriptor); // 注册资源
}

    对于文件写入函数fwrite同样需要修改:
PHP_FUNCTION(sample_fwrite)
{
    php_sample_descriptor_data *fdata;
    zval *file_resource;
    char *data;
    int data_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
            &file_resource, &data, &data_len) == FAILURE ) {
        RETURN_NULL();
    }
    ZEND_FETCH_RESOURCE(fdata, php_