设为首页 收藏本站
查看: 301|回复: 0

[经验分享] PHP资源类型

[复制链接]

尚未签到

发表于 2017-3-4 12:37:03 | 显示全部楼层 |阅读模式
  在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连接未释放问题,也是因为扩展中定义了析构方法,帮助自动释放。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-350207-1-1.html 上篇帖子: php模板简单原理 下篇帖子: php版本说明
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表