PHP资源类型

在PHP中,我们经常使用到资源类型变量。例如:mysql连接、文件句柄等。

这些变量无法使用标量来表示,那么在Zend内核中是如何将PHP中的资源变量与C语言中的资源衔接的呢?

一、资源变量在PHP中的使用

[php] view plain copy

  1. $fp = fopen("test.txt", "rw");
  2. var_dump($fp);
  3. fclose($fp);

打印结果:resource(5) of type (stream)

数字5:表示资源ID为5,具体含义后面介绍。

stream:资源类型名称。

二、资源ID

内核中将注册的资源变量存储在一个HashTable中,并把资源所在HashTable中的key作为资源ID。

所以,实际上PHP中的资源变量实际存储的是一个整型,通过这个ID找到HashTable中对应的资源。

[cpp] view plain copy

  1. #define Z_RESVAL(zval)          (zval).value.lval
  2. #define Z_RESVAL_P(zval)        Z_RESVAL(*zval)
  3. #define Z_RESVAL_PP(zval)       Z_RESVAL(**zval)

上面的宏,是内核中ZE为资源变量赋值的API,看出确实是对整型变量的赋值。

三、资源类型名称

为了区分资源类型,需要为我们定义的资源定义类型名称。

[cpp] view plain copy

  1. #define MY_RES_NAME "my_resource" //资源类型名称,PHP通过var_dump打印资源变量时会看到这个名称
  2. static int my_resource_descriptor;
  3. ZEND_MINIT_FUNCTION(jinyong)
  4. {
  5. my_resource_descriptor = zend_register_list_destructors_ex(NULL, NULL, MY_RES_NAME, module_number);//向内核中注册新的资源类型
  6. }

ZEND_MINIT_FUNCTION(jinyong)会在PHP作为SAPI(例如,Apache的mod_php5扩展)被加载到内存时,会执行所有扩展的ZEND_MINIT_FUNCTION。

其中jinyong,是当前扩展的名字。例如此时扩展的名字就是jinyong

这里为了方便理解,我们就把它认为是扩展在初始化时,会向内核中注册新的资源类型。

四、创建资源变量

资源类型已经注册成功,也为资源定义了区分的类型名称。现在可以使用这种资源的变量了。

实现PHP中的fopen函数:

[cpp] view plain copy

  1. PHP_FUNCTION(my_fopen)
  2. {
  3. zval *res;
  4. char *filename, *mode;
  5. int filename_strlen, mode_strlen;
  6. FILE *fp;
  7. if(zend_parse_parameters(ZEND_NUM_ARGS TSRMLS_CC, "s|s",  &filename, &filename_strlen, &mode, &mode_strlen) == FAILURE){
  8. RETURN_FALSE;
  9. }
  10. //此处省略了对参数的有效性验证
  11. fp = fopen(filename, mode);
  12. ZEND_REGISTER_RESOURCE(res, fp, my_resource_descriptor);//向全局变量&EG(regular_list)中注册资源变量,并将对应HashTable的ID赋值给res
  13. RETURN_RESOURCE(res);//向PHP返回资源变量
  14. }

这里,定义了PHP中名称为my_fopen的函数。my_fopen(string $file_name, string $mode)

实现PHP中的fclose函数:

[cpp] view plain copy

  1. PHP_FUNCTION(my_fclose)
  2. {
  3. zval *res;
  4. FILE *fp;
  5. if(zend_parse_parameters(ZEND_NUM_ARGS TSRMS_CC, "r", &res) == FAILURE){
  6. RETURN_FALSE;
  7. }
  8. if(Z_TYPE_P(res) == IS_RESOURCE){//判断变量类型是否是资源类型
  9. zend_hash_index_del(&EG(regular_list), Z_RESVAL_P(res));//EG就类似于PHP中的$_GLOBALS。在全局资源变量regular_list中删除对应ID的资源
  10. }else{
  11. php_error_docref(NULL TSRMLS_CC, E_WARNING, "参数必须是资源类型变量");
  12. RETURN_FALSE;
  13. }
  14. RETURN_TRUE;
  15. }

定义了PHP中名称为my_fclose的函数。my_fclose($resource)

五、编译、安装扩展,重启php-fpm或mod_php5等

六、PHP中使用自定义扩展中的方法

[php] view plain copy

  1. my_fwrite($fp, "aaTest");
  2. var_dump($fp);
  3. my_fclose($fp);
  4. var_dump($fp);

可以正常,打开和关闭资源。

七、我们在PHP中经常使用数据库连接资源、文件句柄资源,但他们通常无需我们手工释放,也不会出现内存泄漏问题,这是如何实现的呢?

[cpp] view plain copy

  1. my_resource_descriptor = zend_register_list_destructors_ex(NULL, NULL, MY_RES_NAME, module_number);//向内核中注册新的资源类型

回到最开始的注册资源类型,看到zend_register_list_destructors_ex的第一个参数,这个参数就是析构函数的指针。

那么,如果需要实现自动释放功能,只需要定义析构函数并传递函数指针即可。

再看一个问题:

[php] view plain copy

  1. $fp = fopen("test.txt", "rw");
  2. var_dump($fp);
  3. //fclose($fp); 此处不使用fclose释放资源
  4. unset($fp); //而是使用unset释放
  5. //unset没有问题,会正常释放$fp变量。但$fp对应真正的打开文件资源句柄资源将永远释放不了,直至mod_php5或php-fpm重启
  6. //可以看出,在注册资源类型时定义析构函数的必要性了

定义析构函数:

[cpp] view plain copy

  1. static void php_myres_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){//析构函数被调用时,会接受一个当前资源变量的参数
  2. FILE *fp = (FILE*)rsrc->ptr;
  3. fclose(fp);
  4. }
  5. ZEND_MINIT_FUNCTION(jinyong)
  6. {
  7. my_resource_descriptor = zend_register_list_destructors_ex(php_myres_dtor, NULL, MY_RES_NAME, module_number);
  8. }

[cpp] view plain copy

    1. 在PHP中,所谓资源变量,实际都是通过存储整型值,在到内核全局资源变量列表EG(regular_list)中找到对应的指针,并进行相应操作。
    2. 而PHP资源变量,之所以不用担心类似MYSQL连接未释放问题,也是因为扩展中定义了析构方法,帮助自动释放。
时间: 2024-11-08 12:59:15

PHP资源类型的相关文章

现代Web的资源/类型/元素--发展趋势

5月6日,谷歌开发者中心推出了一个 Web 开发最佳实践手册.伯乐在线资源频道摘编该资源后,已邀请一些关注 Web 开发的朋友参与翻译手册. 由于译者朋友几乎都是已在职,都是在工作之余参与,每位的翻译进度会不一样(请理解),所以手册中文版不会按照英文版章节顺序发布. 我们的Web应用程序在规模.野心和功能上持续成长 --这是一件好事.然而,向着更丰富的Web无情进军的过程,也推动了另一种趋势:每个应用程序下载的数据量也在持续稳步增长.为了提供强大的性能,我们需要优化每个字节的加载! 一个现代We

Php学习之资源类型的使用详解

本文和大家分享的主要是php中资源类型的使用相关内容,一起来看看吧,希望对大家 学习php 有所帮助.  资源类型是一种特殊类型,它实际上可以保存任意的C指针,对PHP表现出一个资源对象的模样,例如:PHP里fopen的返回值就是一个resource.  我们可以利用资源类型,保存类型对象的指针,比如:一个FILE*文件描述符,或者仅仅是一个简单的char *字符串,其意义是可以将我们希望传递的C语言内存对象通过zval的形式包装起来,以便C和PHP跨语言传递.  资源类型是一个zval的底层数

puppet资源类型详解(02)

常用的资源类型: notify, cron, exec, service, file, package, group, user (1) notify:利用puppet定义一个信息. message:通知的信息内容 notify {'warning': message=> "From warning notify resource.", } (2) cron ensure: 目标状态 command: 命令 hour minute month monthday weekday n

PHP-Manual的学习----【语言参考】----【类型】-----【Resource 资源类型】

2017年8月24日11:29:361.资源 resource 是一种特殊变量,保存了到外部资源的一个引用.资源是通过专门的函数来建立和使用的.2.由于资源类型变量保存有为打开文件.数据库连接.图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义.3.由于 PHP 4 Zend 引擎引进了引用计数系统,可以自动检测到一个资源不再被引用了(和 Java 一样).这种情况下此资源使用的所有外部资源都会被垃圾回收系统释放.因此,很少需要手工释放内存. 4. 持久数据库连接比较特殊,它们不会被

tomcat命名资源类型

tomcat命名资源类型

Android的资源类型和存储方式简介-android学习之旅(五十二)

android资源的类型 android资源的存储方式

资源类型

资源是一种特殊变量,保存了到外部资源的一个引用.资源是通过专门的函数来建立和使用的. 转换为资源 由于资源类型变量保存有为打开文件\数据库连接\图形画布区域等的特殊句柄,因此将其他类型的值转换为资源没有意义. 释放资源 由于PHP 4 Zend引擎引用了引用计数系统,可以自动检测到一个资源不再被利用(和Java一样).这种情况下此资源使用的 所有外部资源都被垃圾回收系统释放.因此,很少需要手工释放内存. Note: 持久数据库连接比较特殊,它们不会被垃圾回收系统销毁.

ES按资源类型统计个数

一.目标:统计各类型资源的个数,输出详细报表 http://10.10.6.225:9200/dsideal_db/t_resource_info/ _mapping {  "properties": {    "RESOURCE_FORMAT": {       "type":     "text",      "fielddata": true    }  }} 返回结果:{ "acknowl

Azure按订阅,资源组,资源类型导出所有资源powershell命令

一般可以借助powershell命令来读取资源:例如:1, 读取某个订阅下的资源:$subscriptionID = "xxxxxxxx"Set-AzureRmContext $subscriptionIDGet-AzureRMResource  | export-csv allresource.csv 2, 读取某个订阅下的某个资源组下的所有资源:$subscriptionID = "xxxxxxxx"Set-AzureRmContext $subscriptio