Home Backend Development PHP Tutorial PHP extension and embedding--resource data type 2_PHP tutorial

PHP extension and embedding--resource data type 2_PHP tutorial

Jul 13, 2016 am 10:31 AM
data type resource

Complex data types stored in resource variables often require some memory allocation, CPU time, or network communication during initialization. But retaining resources like database connections between requests must be durable. Durability of resources is a factor that must be considered.
First look at the issue of memory allocation: When using PHP, I prefer to use emalloc because it is the recycled version of malloc. But persistent resources must exist between requests. For a file handle resource, if you want to add a requirement to store file names, you must add the following code to the header file:

typedef struct _php_sample_descriptor_data {
    char *filename;
    FILE *fp;
} php_sample_descriptor_data;
Copy after login
Use this structure to store filename and file handle resources so they can be shared between different requests.
Correspondingly, make corresponding changes in the source file:
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);
}
Copy after login
This static function is used to recycle resources and requires a specified callback when initializing resources.
To perform the modified file opening function, you need to add the operation of allocating space to resources:
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;
    }
    <strong>fdata = emalloc(sizeof(php_sample_descriptor_data)); //给包含了文件资源和文件名的结构分配空间
    fdata->fp = fp;
    fdata->filename = estrndup(filename, filename_len);</strong>
    ZEND_REGISTER_RESOURCE(return_value, fdata,
                                le_sample_descriptor); // 注册资源
}
Copy after login

The file writing function fwrite also needs to be modified:
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",
            &amp;file_resource, &amp;data, &amp;data_len) == FAILURE ) {
        RETURN_NULL();
    }
    <strong>ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*,
        &amp;file_resource, -1,
        PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor);</strong>
    RETURN_LONG(fwrite(data, 1, data_len, fdata->fp));
} 
Copy after login

Nothing needs to be changed for the sample_fclose function because it does not operate on actual resources. The following function can get the original file name from the resource:
PHP_FUNCTION(sample_fname)
{
    php_sample_descriptor_data *fdata;
    zval *file_resource;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
            &amp;file_resource) == FAILURE ) {
        RETURN_NULL();
    }
    <strong>ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*,
        &amp;file_resource, -1,
        PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor);</strong>
    RETURN_STRING(fdata->filename, 1);
} 
Copy after login


After the memory allocation is completed, since persistence must be maintained, it must be delayed destruction:
For non-persistent resources, once the variables storing the resource id are unset or fall out of scope, they are removed from the EG (regular_list). The index used in EG (persistent_list) is key-value type, and the elements will not be automatically removed at the end of the request. Only eliminated if zend_hash_del() is called or the thread/process is shut down completely. EG (persistent_list) also has a dtor method, but it is the second parameter of zend_register_list_descructors_ex(). Generally speaking, non-persistent and persistent resources will be registered as two types, and sometimes they can be combined into one. Now add a persistent resource type in sample.c.
    static int le_sample_descriptor_persist;
    static void php_sample_descriptor_dtor_persistent(
                    zend_rsrc_list_entry *rsrc TSRMLS_DC)
{<strong>//这是一个持久化的资源析构函数</strong>
    php_sample_descriptor_data *fdata =
                (php_sample_descriptor_data*)rsrc->ptr;
    <strong>fclose(fdata->fp);
    pefree(fdata->filename, 1);
    pefree(fdata, 1);</strong>
}
PHP_MINIT_FUNCTION(sample)
{
    le_sample_descriptor =     zend_register_list_destructors_ex(
            php_sample_descriptor_dtor, NULL,
            PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number);
    <strong>le_sample_descriptor_persist =
                        zend_register_list_destructors_ex(
            NULL, php_sample_descriptor_dtor_persistent,
            PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number);//注册一个持久化的资源</strong>
    return SUCCESS;
} 
Copy after login

The fopen function below is compatible with both persistent and non-persistent resource types:
PHP_FUNCTION(sample_fopen)
{
    php_sample_descriptor_data *fdata;
    FILE *fp;
    char *filename, *mode;
    int filename_len, mode_len;
    zend_bool persist = 0;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss|b",
                &amp;filename, &amp;filename_len, &amp;mode, &amp;mode_len,
                &amp;persist) == 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;
    }
    if (!persist) {//非持久化的资源
        fdata = emalloc(sizeof(php_sample_descriptor_data));
        fdata->filename = estrndup(filename, filename_len);//这个做了申请内存和赋值两步操作 
        fdata->fp = fp;
        ZEND_REGISTER_RESOURCE(return_value, fdata,
                                le_sample_descriptor);
    } else {//持久化的资源
        list_entry le;
        char *hash_key;          
        int hash_key_len;
        fdata =pemalloc(sizeof(php_sample_descriptor_data),1);
        fdata->filename = pemalloc(filename_len + 1, 1);
        memcpy(fdata->filename, filename, filename_len + 1);
        fdata->fp = fp;
        ZEND_REGISTER_RESOURCE(return_value, fdata,
                        le_sample_descriptor_persist);

        /* Store a copy in the persistent_list 在persistent_list存储一份副本 */
        le.type = le_sample_descriptor_persist;
        le.ptr = fdata;
        hash_key_len = spprintf(&amp;hash_key, 0,
                "sample_descriptor:%s:%s", filename, mode);
        zend_hash_update(&amp;EG(persistent_list),
            hash_key, hash_key_len + 1,
            (void*)&amp;le, sizeof(list_entry), NULL);
        efree(hash_key);
    }
} 
Copy after login

For non-persistent resources, a numeric index is given and stored in a request-dependent list. For persistent resources, given a key value type, the hashkey can be retrieved on subsequent requests. Then put the resource into the persistent list. When a persistent resource goes out of scope, the destructor of EG (regular_list) checks the registerlist destructor for le_sample_descriptro_persist. If it is found to be NULL, no operation will be performed. This ensures that persistent resources will not be released. When a resource is removed from the EG (persistent_list), either the thread process ends or it is deleted intentionally. At this time, you will look for the persistent destructor.

The reason why resources are applied for persistence is to reuse in other requests:
If you want to reuse persistent resources, you must use hash_key. When sample_fopen is called, the function will recreate the hash_key using the requested file name and mode, and then try to find it in the persistent_list.
PHP_FUNCTION(sample_fopen)
{
    php_sample_descriptor_data *fdata;
    FILE *fp;
    char *filename, *mode, *hash_key;
    int filename_len, mode_len, hash_key_len;
    zend_bool persist = 0; //判断是否持久
    list_entry *existing_file;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss|b",
                &amp;filename, &amp;filename_len, &amp;mode, &amp;mode_len,
                &amp;persist) == FAILURE) {
        RETURN_NULL();
    }
    if (!filename_len || !mode_len) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                "Invalid filename or mode length");
        RETURN_FALSE;
    }
    <strong>/* 通过获得一个hash_key尝试寻找一个已经打开的文件 */
    hash_key_len = spprintf(&amp;hash_key, 0,
            "sample_descriptor:%s:%s", filename, mode);
                                                                                                              
    if (zend_hash_find(&amp;EG(persistent_list), hash_key,
            hash_key_len + 1, (void **)&amp;existing_file) == SUCCESS) {
        /* 成功的找到了这个已经打开的文件句柄资源 */
        ZEND_REGISTER_RESOURCE(return_value,
            existing_file->ptr, le_sample_descriptor_persist);
        efree(hash_key);
        return;
    }</strong>
    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;
    }
    if (!persist) {
        fdata = emalloc(sizeof(php_sample_descriptor_data));
        fdata->filename = estrndup(filename, filename_len);
        fdata->fp = fp;
        ZEND_REGISTER_RESOURCE(return_value, fdata,
                                le_sample_descriptor);
    } else {
        list_entry le;
        fdata =pemalloc(sizeof(php_sample_descriptor_data),1);
        fdata->filename = pemalloc(filename_len + 1, 1);
        memcpy(data->filename, filename, filename_len + 1);
        fdata->fp = fp;
        ZEND_REGISTER_RESOURCE(return_value, fdata,
                        le_sample_descriptor_persist);
        /* Store a copy in the persistent_list */
        le.type = le_sample_descriptor_persist;
        le.ptr = fdata;
        /* hash_key has already been created by now */
        zend_hash_update(&amp;EG(persistent_list),
            hash_key, hash_key_len + 1,
            (void*)&amp;le, sizeof(list_entry), NULL);
    }
    efree(hash_key);
}
Copy after login

Note that naming is important since all extensions use the same hash form to store resources. Generally, extension and resource type names are used as prefixes.

Check resource availability:
While resources like files can be open for long periods of time, resources like remote network resources are problematic if they are not used for long periods of time between requests. Therefore, before using a persistent resource, you must first determine the availability.
if (zend_hash_find(&amp;EG(persistent_list), hash_key,
        hash_key_len + 1, (void**)&amp;socket) == SUCCESS) {
    if (php_sample_socket_is_alive(socket->ptr)) {
        ZEND_REGISTER_RESOURCE(return_value,
                    socket->ptr, le_sample_socket);
        return;
    }
    zend_hash_del(&amp;EG(persistent_list),
                            hash_key, hash_key_len + 1); //这里会去调用之前注册好的析构函数
}
Copy after login









www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/762935.htmlTechArticleComplex data types stored in resource variables usually require some memory allocation, CPU time or network communication during initialization . But retain resources like database connections between requests...
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot Article Tags

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Use ddrescue to recover data on Linux Use ddrescue to recover data on Linux Mar 20, 2024 pm 01:37 PM

Use ddrescue to recover data on Linux

Open source! Beyond ZoeDepth! DepthFM: Fast and accurate monocular depth estimation! Open source! Beyond ZoeDepth! DepthFM: Fast and accurate monocular depth estimation! Apr 03, 2024 pm 12:04 PM

Open source! Beyond ZoeDepth! DepthFM: Fast and accurate monocular depth estimation!

Google is ecstatic: JAX performance surpasses Pytorch and TensorFlow! It may become the fastest choice for GPU inference training Google is ecstatic: JAX performance surpasses Pytorch and TensorFlow! It may become the fastest choice for GPU inference training Apr 01, 2024 pm 07:46 PM

Google is ecstatic: JAX performance surpasses Pytorch and TensorFlow! It may become the fastest choice for GPU inference training

The vitality of super intelligence awakens! But with the arrival of self-updating AI, mothers no longer have to worry about data bottlenecks The vitality of super intelligence awakens! But with the arrival of self-updating AI, mothers no longer have to worry about data bottlenecks Apr 29, 2024 pm 06:55 PM

The vitality of super intelligence awakens! But with the arrival of self-updating AI, mothers no longer have to worry about data bottlenecks

Slow Cellular Data Internet Speeds on iPhone: Fixes Slow Cellular Data Internet Speeds on iPhone: Fixes May 03, 2024 pm 09:01 PM

Slow Cellular Data Internet Speeds on iPhone: Fixes

The first robot to autonomously complete human tasks appears, with five fingers that are flexible and fast, and large models support virtual space training The first robot to autonomously complete human tasks appears, with five fingers that are flexible and fast, and large models support virtual space training Mar 11, 2024 pm 12:10 PM

The first robot to autonomously complete human tasks appears, with five fingers that are flexible and fast, and large models support virtual space training

The U.S. Air Force showcases its first AI fighter jet with high profile! The minister personally conducted the test drive without interfering during the whole process, and 100,000 lines of code were tested for 21 times. The U.S. Air Force showcases its first AI fighter jet with high profile! The minister personally conducted the test drive without interfering during the whole process, and 100,000 lines of code were tested for 21 times. May 07, 2024 pm 05:00 PM

The U.S. Air Force showcases its first AI fighter jet with high profile! The minister personally conducted the test drive without interfering during the whole process, and 100,000 lines of code were tested for 21 times.

Alibaba 7B multi-modal document understanding large model wins new SOTA Alibaba 7B multi-modal document understanding large model wins new SOTA Apr 02, 2024 am 11:31 AM

Alibaba 7B multi-modal document understanding large model wins new SOTA

See all articles