PHP资源类型
在PHP中,我们经常使用到资源类型变量。例如:mysql连接、文件句柄等。
这些变量无法使用标量来表示,那么在Zend内核中是如何将PHP中的资源变量与C语言中的资源衔接的呢?
一、资源变量在PHP中的使用
- $fp = fopen("test.txt", "rw");
- var_dump($fp);
- fclose($fp);
打印结果:resource(5) of type (stream)
数字5:表示资源ID为5,具体含义后面介绍。
stream:资源类型名称。
二、资源ID
内核中将注册的资源变量存储在一个HashTable中,并把资源所在HashTable中的key作为资源ID。
所以,实际上PHP中的资源变量实际存储的是一个整型,通过这个ID找到HashTable中对应的资源。
- #define Z_RESVAL(zval) (zval).value.lval
- #define Z_RESVAL_P(zval) Z_RESVAL(*zval)
- #define Z_RESVAL_PP(zval) Z_RESVAL(**zval)
上面的宏,是内核中ZE为资源变量赋值的API,看出确实是对整型变量的赋值。
三、资源类型名称
为了区分资源类型,需要为我们定义的资源定义类型名称。
- #define MY_RES_NAME "my_resource" //资源类型名称,PHP通过var_dump打印资源变量时会看到这个名称
- static int my_resource_descriptor;
- ZEND_MINIT_FUNCTION(jinyong)
- {
- my_resource_descriptor = zend_register_list_destructors_ex(NULL, NULL, MY_RES_NAME, module_number);//向内核中注册新的资源类型
- }
ZEND_MINIT_FUNCTION(jinyong)会在PHP作为SAPI(例如,Apache的mod_php5扩展)被加载到内存时,会执行所有扩展的ZEND_MINIT_FUNCTION。
其中jinyong,是当前扩展的名字。例如此时扩展的名字就是jinyong
这里为了方便理解,我们就把它认为是扩展在初始化时,会向内核中注册新的资源类型。
四、创建资源变量
资源类型已经注册成功,也为资源定义了区分的类型名称。现在可以使用这种资源的变量了。
实现PHP中的fopen函数:
- PHP_FUNCTION(my_fopen)
- {
- zval *res;
- char *filename, *mode;
- int filename_strlen, mode_strlen;
- FILE *fp;
- if(zend_parse_parameters(ZEND_NUM_ARGS TSRMLS_CC, "s|s", &filename, &filename_strlen, &mode, &mode_strlen) == FAILURE){
- RETURN_FALSE;
- }
- //此处省略了对参数的有效性验证
- fp = fopen(filename, mode);
- ZEND_REGISTER_RESOURCE(res, fp, my_resource_descriptor);//向全局变量&EG(regular_list)中注册资源变量,并将对应HashTable的ID赋值给res
- RETURN_RESOURCE(res);//向PHP返回资源变量
- }
这里,定义了PHP中名称为my_fopen的函数。my_fopen(string $file_name, string $mode)
实现PHP中的fclose函数:
- PHP_FUNCTION(my_fclose)
- {
- zval *res;
- FILE *fp;
- if(zend_parse_parameters(ZEND_NUM_ARGS TSRMS_CC, "r", &res) == FAILURE){
- RETURN_FALSE;
- }
- if(Z_TYPE_P(res) == IS_RESOURCE){//判断变量类型是否是资源类型
- zend_hash_index_del(&EG(regular_list), Z_RESVAL_P(res));//EG就类似于PHP中的$_GLOBALS。在全局资源变量regular_list中删除对应ID的资源
- }else{
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "参数必须是资源类型变量");
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
定义了PHP中名称为my_fclose的函数。my_fclose($resource)
五、编译、安装扩展,重启php-fpm或mod_php5等
六、PHP中使用自定义扩展中的方法
- my_fwrite($fp, "aaTest");
- var_dump($fp);
- my_fclose($fp);
- var_dump($fp);
可以正常,打开和关闭资源。
七、我们在PHP中经常使用数据库连接资源、文件句柄资源,但他们通常无需我们手工释放,也不会出现内存泄漏问题,这是如何实现的呢?
- my_resource_descriptor = zend_register_list_destructors_ex(NULL, NULL, MY_RES_NAME, module_number);//向内核中注册新的资源类型
回到最开始的注册资源类型,看到zend_register_list_destructors_ex的第一个参数,这个参数就是析构函数的指针。
那么,如果需要实现自动释放功能,只需要定义析构函数并传递函数指针即可。
再看一个问题:
- $fp = fopen("test.txt", "rw");
- var_dump($fp);
- //fclose($fp); 此处不使用fclose释放资源
- unset($fp); //而是使用unset释放
- //unset没有问题,会正常释放$fp变量。但$fp对应真正的打开文件资源句柄资源将永远释放不了,直至mod_php5或php-fpm重启
- //可以看出,在注册资源类型时定义析构函数的必要性了
定义析构函数:
- static void php_myres_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){//析构函数被调用时,会接受一个当前资源变量的参数
- FILE *fp = (FILE*)rsrc->ptr;
- fclose(fp);
- }
- ZEND_MINIT_FUNCTION(jinyong)
- {
- my_resource_descriptor = zend_register_list_destructors_ex(php_myres_dtor, NULL, MY_RES_NAME, module_number);
- }
- 在PHP中,所谓资源变量,实际都是通过存储整型值,在到内核全局资源变量列表EG(regular_list)中找到对应的指针,并进行相应操作。
- 而PHP资源变量,之所以不用担心类似MYSQL连接未释放问题,也是因为扩展中定义了析构方法,帮助自动释放。
PHP资源类型的更多相关文章
- php扩展开发-资源类型
资源类型在内核中的结构 //zend_list.h typedef struct _zend_rsrc_list_entry { void *ptr; int type; int refcount; ...
- [置顶]
kubernetes资源类型--PetSets/StatefulSet
PetSet首次在K8S1.4版本中,在1.5更名为StatefulSet.除了改了名字之外,这一API对象并没有太大变化. 注意:以下内容的验证环境为CentOS7.K8S版本1.5.2,并部署Sk ...
- [置顶]
kubernetes资源类型--持久化存储Persistent Volume和Persistent Volume Claim
概念 存储管理跟计算管理是两个不同的问题.理解每个存储系统是一件复杂的事情,特别是对于普通用户来说,有时并不需要关心各种存储实现,只希望能够安全可靠地存储数据. 为了简化对存储调度,K8S对存储的供应 ...
- PHP-Manual的学习----【语言参考】----【类型】-----【Resource 资源类型】
2017年8月24日11:29:361.资源 resource 是一种特殊变量,保存了到外部资源的一个引用.资源是通过专门的函数来建立和使用的.2.由于资源类型变量保存有为打开文件.数据库连接.图形画 ...
- PHP的资源类型
PHP的资源类型 php的资源类型 常见的有:打开文件.数据库连接.图形画布等. 常用操作:创建.使用.释放. 以文件操作为示例: //文件路径 $file_url = './data.txt'; / ...
- 关于k8s资源类型和缩写
资源类型 缩写 描述 clusters componentstatuses cs configmaps cm daemonsets ds deployments deploy ...
- 现代Web的资源/类型/元素--发展趋势
5月6日,谷歌开发者中心推出了一个 Web 开发最佳实践手册.伯乐在线资源频道摘编该资源后,已邀请一些关注 Web 开发的朋友参与翻译手册. 由于译者朋友几乎都是已在职,都是在工作之余参与,每位的翻译 ...
- Kubernets 资源类型简介
# Node 代表 Kubernets 集群运行的宿主物理机或者虚拟服务器, 为容器提供必要的计算资源: 内存 与 CPU 等. # Pod 最底层的抽象. 一个 Pod 中可以包含一个或者多个运行的 ...
- Android的资源类型和存储方式简介-android学习之旅(五十二)
android资源的类型 android资源的存储方式
随机推荐
- javascript: 常用操作
1,取得输入框的输入值,修改输入框的输入值 根据id获取id的值 jquery代码: $('#version_number').val(); 解释:$是jQuery的标准用法,('#version_n ...
- KVM 虚拟机基本管理及常用命令
KVM的基本管理 1.查看KVM虚拟机配置文件 #Kvm虚拟机默认配置文件位置 [root@kvm qemu]# pwd /etc/libvirt/qemu [root@kvm qemu]# ll t ...
- Thrift源码解析--TBinaryProtocol
本文为原创,未经许可禁止转载. 关于Tprotocol层都是一些通信协议,个人感觉内容较大,很难分类描述清楚.故打算以TBinaryProtocol为例,分析客户端发请求以及接收服务端返回数据的整个过 ...
- 计算机网络 NAT
NAT(Network Address Translation,网络地址转换)是1994年提出的.当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因 ...
- DateUtils时间工具类探究
首先声明一下,这个DateUtils工具类不是自己写的,而是在commons-lang-2.Xjar包或是commons-lang3-3.X.jar包中,具体在哪个jar包中,看程序具体添加了哪个版本 ...
- 初探OpenGL(一)
OPenGL ES 1.X 面向功能固定的硬件所涉及并提供加速支持,图形质量以及性能标准. OpenGL ES2.X则提供包括着色器技术在内的全编程3D图形算法.----硬件要求比较高. OpenGL ...
- HDU 5765 Bonds
比赛时候想了好久,不会.看了官方题解才会...... Bond是极小割边集合,去掉一个Bond之后,只会将原图分成两个连通块. 假设某些点构成的集合为 s(点集中的点进行状压后得到的一个十进制数),那 ...
- VBS调用系统API
如Beep的API声明为 Public Declare Function Beep Lib “kernel32″ Alias “Beep” (ByVal dwFreq As Long, ByVal d ...
- hdu_5787_K-wolf Number(数位DP)
题目链接:hdu_5787_K-wolf Number 题意: 给你一个区间,让你找满足任意k个数位内都没有相同的数字的个数 题解: 因为k不大,就直接将当前pos的前k-1个数传进去就行了 #inc ...
- 缩放系列(二):所有子控件也随着缩放、手势缩放、多点触控layout
下面是一个功能强大的改造的例子: 可以实现以下需求: 1.两个手指进行缩放布局 2.所有子控件也随着缩放, 3.子控件该有的功能不能丢失(像button有可被点击的功能,缩放后不能丢失该功能) 运行效 ...