PHP的资源数据类型

资源数据类型

迄今为止, 你都是工作在非常基础的用户空间数据类型上, 字符串, 数值, TRUE/FALSE等值. 即便上一章你已经开始接触数组了, 但也只是收集这些基础数据类型的数组.

复杂的结构体

现实世界中, 你通常需要在更加复杂的数据集合下工作, 通常涉及到晦涩的结构体指针. 一个常见的晦涩的结构体指针示例就是stdio的文件描述符, 即便是在C语言中也只是一个指针.

#include <stdio.h>
int main(void)
{
    FILE *fd;
    fd = fopen("/home/jdoe/.plan", "r");
    fclose(fd);
    return 0;
}

stdio的文件描述符和其他多数文件描述符一致, 都像是一个书签. 你扩展的调用应用仅需要在feof(), fread(), fwrite(), fclose()这样的实现函数调用时传递这个值. 有时, 这个书签必须是用户空间代码可访问的; 因此, 就需要在标准的php变量或者说zval *中有表示它的方法.

这里就需要一种新的数据类型. RESOURCE数据类型在zval *中存储一个简单的整型值, 使用作为已注册资源的索引用来查找. 资源条目包含了资源索引所表示的内部数据类型, 以及存储资源数据的指针等信息.

定义资源类型

为了使注册的资源条目所包含的资源信息更加明确, 需要定义资源的类型. 首先在你的sample.c中已有的函数实现下增加下面的代码片段

static int le_sample_descriptor;
PHP_MINIT_FUNCTION(sample)
{
    le_sample_descriptor = zend_register_list_destructors_ex(
                NULL, NULL, PHP_SAMPLE_DESCRIPTOR_RES_NAME,
                module_number);
    return SUCCESS;
}

接下来, 滚动到你的代码文件末尾, 修改sample_module_entry结构体, 将NULL, /* MINIT */一行替换为下面的内容. 就像你给这个结构中增加函数列表结构时一样, 你需要确认在这一行末尾保留一个逗号.

PHP_MINIT(sample), /* MINIT */  

最后, 你需要在php_sample.h中定义PHP_SAMPLE_DESCRIPTOR_RES_NAME, 将下面的代码放到你的其他常量定义下面:

#define PHP_SAMPLE_DESCRIPTOR_RES_NAME "File Descriptor"  

PHP_MINIT_FUNCTION()代表第1章"PHP生命周期"中介绍的4个特殊的启动和终止操作中的第一个, 关于生命周期, 在第12章"启动, 终止以及之间的几个关键点"和第13章"INI设置"中还将深入讨论.

这里需要知道的非常重要的一点是MINIT函数在你的扩展第一次加载时执行一次, 它会在所有请求到达之前被执行. 这里我们利用这个机会注册了析构函数, 不过它们是NULL值, 不过在通过一个唯一整型ID足以知道一个资源类型时, 你很快就会修改它.

注册资源

现在引擎已经知道了你要存储一些资源数据, 是时候给用户空间的代码一种方式去产生实际的资源了. 要做到这一点, 需要如下重新实现fopen()命令:

PHP_FUNCTION(sample_fopen)
{
    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;
    }
    ZEND_REGISTER_RESOURCE(return_value, fp,
                                le_sample_descriptor);
}

为了让编译器知道什么是FILE *, 你需要包含stdio.h. 这可以放在sample.c中, 但是为了本章后面部分做准备, 我还是要求你放到php_sample.h中.

如果你对前面的章节付出了努力, 最后一行前面的所有内容都应该可以读懂. 这一行代码执行的任务是将fp指针存储到资源的索引中, 将它和MINIT中定义的类型关联起来, 并存储一个可用于查找的key到return_value中.

如果需要存储多于一个指针的值, 或者存储一个直接量, 则必须新分配一段内存用来存储数据, 接着将指向这段内存的指针注册为资源.

译注:

1. 资源数据类型的注册实际上是在list_destructors(Zend/zend_list.c中定义的静态全局变量HashTable)中插入一个新构建的zend_rsrc_list_dtors_entry结构体, 这个结构体描述了这个资源类型的信息.

2. 资源数据的注册(ZEND_REGISTER_RESOURCE)实际上是在EG(regular_list)中使用zend_hash_next_free_element()得到下一个数值下标, 作为资源的ID, 并将传入的资源指针(封装为zend_rsrc_list_entry结构体)存储到EG(regular_list)中这个下标对应的元素中.

3. EG(regular_list)的初始化是在请求初始化阶段完成的, 通过跟踪代码, 可以看到其函数调用流程如下: php_request_startup(main/main.c) --> zend_active(Zend/zend.c) --> init_compiler(Zend/zend_compile.c) --> zend_init_rsrc_list(Zend/zend_list.c). 通过观察zend_init_rsrc_list()函数可以看出EG(regular_list)的析构函数是list_entry_destructor(Zend/zend_list.c). 而list_entry_destructor()的逻辑是从list_destructors(上面第一步所述的静态全局变量)中查找要释放的资源对象类型的信息, 接着按照注册资源类型时所指定的析构器进行析构.

4. 按照上面几点, 可以很容易理清本章前面所述内容. 首先注册一个资源类型, 这个资源类型中包含了诸如所属模块编号, 析构器句柄这样的信息. 接着, 在创建具体的资源对象时, 将资源对象和资源类型做了一个关联.

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索指针
, 结构体指针
, 函数
, 数据类型
, 类型
, 资源
, 一个
return_false
php 资源类型、php资源类型是什么、php 数据类型、php 数据类型转换、php 判断数据类型,以便于您获取更多的相关知识。

时间: 2024-11-03 20:12:57

PHP的资源数据类型的相关文章

php扩展与嵌入--资源数据类型2

在资源变量中存储的复杂的数据类型通常在初始化时需要一些内存分配,CPU时间或网络通信.但是在请求之间保留类似于数据库连接这种资源,必须要做到持久.资源是否持久是一个必须要考虑到的因素. 首先看内存分配的问题: 在使用php的时候,偏向使用emalloc因为它是malloc的带回收的版本.但是持久化的资源必须在请求间都存在.对于一个文件句柄类的资源来说,如果要加入一个存储文件名的需求,那么必须在头文件中加入如下的代码: typedef struct _php_sample_descriptor_d

php扩展和嵌入式编程基础

php的生命周期详解 php变量的研究 php内存管理详解 安装构建php环境 编写第一个php扩展 php函数的返回值 php扩展函数接受参数 php如何在数组和哈希表上工作 PHP的资源数据类型 php4的对象详解 详解php5对象 详解php的启动过程 php的INI设置 php中流的访问 php中流的实现 php中有趣的流 php源代码的配置和链接 php的扩展自动生成 设置嵌入php的宿主环境 php的高级嵌入式

php的扩展自动生成

扩展生成 毫无疑问你已经注意到, 每个php扩展都包含一些非常公共的并且非常单调的结构和文件. 当开始一个新扩展开发的时候, 如果这些公共的结构已经存在, 我们只用考虑填充功能代码是很有意义的. 为此, 在php中包含了一个简单但是很有用的shell脚本. ext_skel 切换到你的php源代码树下ext/目录中, 执行下面的命令: jdoe@devbox:/home/jdoe/cvs/php-src/ext/$ ./ext_skel extname=sample7   稍等便可, 输出一些文

详解php5对象

php5对象 将php5的对象和它的先辈php4对象进行比较实在有些不公平, 不过php5对象使用的API函数还是遵循php4的API构建的. 如果你已经阅读了第10章"php4对象", 你将会对本章内容多少有些熟悉. 在开始本章之前, 可以像第10章开始时一样, 重命名扩展为sample3并清理多余的代码, 只保留扩展的骨架代码. 进化史 在php5对象变量中有两个关键的组件. 第一个是一个数值的标识, 它和第9章"资源数据类型"中介绍的数值资源ID非常相似, 扮

Android 4.0 开发者指南(28) —— Resource Types - More Types

前言 本章内容为Android开发者指南的Framework Topics/Application Resources/Resource Types/More Types章节,译为"更多资源类型",版本为Android 4.0 r1,翻译来自:"呆呆大虾",欢迎访问他的微博:"http://weibo.com/popapa",再次感谢"呆呆大虾" !期待你一起参与翻译Android的相关资料,联系我over140@gmail.

TensorFlow教程之资源 4.6 张量的阶、形状、数据类型

本文档为TensorFlow参考文档,本转载已得到TensorFlow中文社区授权. 张量的阶.形状.数据类型 TensorFlow用张量这种数据结构来表示所有的数据.你可以把一个张量想象成一个n维的数组或列表.一个张量有一个静态类型和动态类型的维数.张量可以在图中的节点之间流通. 阶 在TensorFlow系统中,张量的维数来被描述为阶.但是张量的阶和矩阵的阶并不是同一个概念.张量的阶(有时是关于如顺序或度数或者是n维)是张量维数的一个数量描述.比如,下面的张量(使用Python中list定义

关于PHP中常见数据类型的汇总

 本文整理了有关于PHP中常见的数据类型,感兴趣的朋友可以参考下 PHP 数据类型    PHP 支持八种原始类型(type).    四种标量类型:  string(字符串)  integer(整型)  float(浮点型,也作 double )  boolean(布尔型)    两种复合类型:  array(数组)  object(对象)    两种特殊类型:  resource(资源)  NULL(空)    查看变量类型    通过 gettype() 函数可以方便的查看某个变量的类型:

android应用资源预编译,编译和打包全解析

我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的.在打包之前,大部分文本格式的XML资源文件还会被编译成二进制格式的XML资源文件.在本文中,我们就详细分析XML资源文件的编译和打包过程,为后面深入了解Android系统的资源管理框架打下坚实的基础.         在前面Android资源管理框架(Asset Manager)简要介绍和学习计划一

使用 SQLXML 数据类型

xml|数据|数据类型 概述 J2EE 开发人员通常需要在关系数据库中存储 XML 文档以及从数据库中检索 XML 文档,以获得元素值和属性值.目前,只有特定于供应商的技术和数据类型可用于在关系数据库中存储 XML 文档.例如 IBM DB2 Universal Database (UDB) 提供了 DB2 XML Extender 和 XML 用户定义类型 (UDT) 来存储 XML 文档.用于 XML 类型列的标准数据类型和对应于 XML 类型列的 Java 数据类型将促进关系数据库中 XM