php什么叫资源型,PHP扩展开发之资源类型
本章内容
本章主要介绍 php7 资源类型的使⽤,最终封装⼀个⾃⼰的⽂件操作函数。
什么是资源
resource 是 php 的⼀种特殊类型,经常⽤于标志各种抽象的东西,⽐如⽂件句柄,流……
资源是怎么实现的?
资源在 php 中⽤ zend_resource 标识,其结构体如下:
// Zend/zend_types.h
struct _zend_resource {
zend_refcounted_h gc;
int handle; // TODO: may be removed
int type;
void *ptr;
};
其中 type 代表资源类型,区分不同的资源。ptr 指针是资源的实际类型,这个是最重要的,围绕资源的⼏乎所有操作都围绕这个字段展开。
关于 zend_resource 的操作,都在 Zend/zend_list.c 中,包括资源的注册,资源的获取。
资源注册
要使⽤资源,必须先注册资源。注册资源使⽤ ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld,
rsrc_dtor_func_t pld, const char *type_name, int module_number) 。第1个参数很重要,是资源的销毁函数,因为 php 语⾔属于⾼级语⾔,⽤户很可能在使⽤完资源后忘记释放,⽐如通过 fopen 打开的⽂件描述符,在 C 中,如果不调⽤ fclo 可能会造成严重的后果,所以在 php 中我们必须考虑这点,通过注册资源的时候传递销毁函数,php 会在脚本结束⾃动帮我们释放资源;第2个参数⼀般传NULL 就好;第3个就是资源类型名;第4个是模块的标志。
通常,我们需要在 php 的 MINIT 阶段调⽤资源注册函数。
⽣成资源
小学五年级下册英语⽣成资源使⽤ ZEND_API zend_resource* zend_register_resource(void *rsrc_pointer, int rsrc_type) ,第1个参数就是资源的ptr,实际使⽤到的内容,⽐如⼀般把 FILE *fp 放在这⾥;第2个参数是资源类型。
解析资源
fopen ⽣成资源后,⽤户再调 fwrite 的时候传⼊ $ch ,我们需要从 ch ⾥⾯解析出 FILE *fp ;解析资源使⽤的函数是 ZEND_API void *zend_fetch_resource(zend_resource *res, const char *resource_type_name, int resource_type) ,参数名称也都是字解释的。
Demo
接下来,我们⾃⼰实现两个函数 pure_open(filename,mode),pure_write(ch,content)。
// resource_demo.c
//
// Created by purelightme on 2020/8/25.
//
#include东北电力大学是几本
#include "zend_types.h"
static int le_pf;
#define le_pf_name "just_test"
// 使⽤ struct 存储资源实际内容,⽅便扩展
typedef struct pfile_ch {
FILE *p;
} pfilech;
资源节约与环保static void file_dtor(zend_resource *rsrc)
螳螂的种类
{
pfilech *pch = (pfilech *) rsrc->ptr;
fclo(pch->p);
}
PHP_FUNCTION(pure_open)
{
FILE *fp;
pfilech *pch;
char *path;
long path_len;
char *mode;
long mode_len;
ZEND_PARSE_PARAMETERS_START(2,2)
Z_PARAM_STRING(path,path_len)
Z_PARAM_STRING(mode,mode_len)
ZEND_PARSE_PARAMETERS_END();
fp = fopen(path,mode);
if (fp == NULL){
RETURN_NULL();
}
pch = ecalloc(1,sizeof(pfilech));
pch->p = fp;
ZVAL_RES(return_value,zend_register_resource(pch,le_pf)); }
PHP_FUNCTION(pure_write)
{
zval *res;
pfilech *pch;
char *content;
long content_len;
ZEND_PARSE_PARAMETERS_START(2,2)
Z_PARAM_RESOURCE(res)
Z_PARAM_STRING(content,content_len)
ZEND_PARSE_PARAMETERS_END();
pch = (pfilech *)zend_fetch_resource(Z_RES_P(res),le_pf_name,le_pf);
if (pch == NULL){
温室效应的意思
php_printf("解析资源失败");
RETURN_NULL();
}
fputs(content,pch->p);
RETURN_NULL();
weeknd
}
// purelightme.c
#include "resource_demo.c"
//...
PHP_MINIT_FUNCTION(purelightme)
爱护牙齿教案{
REGISTER_INI_ENTRIES();
le_pf = zend_register_list_destructors_ex(file_dtor,NULL,le_pf_name,module_number); return SUCCESS;
}
重新编译扩展
男狗女猪make clean
make && make install
php测试
$fp = pure_open("/tmp/test.log","aw+");
var_dump($fp);
$res = pure_write($fp,"测试⽂本,hello");
var_dump($res);
18.1.png
⼩结
有了资源类型,php 可以很⽅便的做很多事情,只要是进程共享的资源,都可以⽤资源类型实现。⽐如我们可以⽤ epoll 实现 io多路复⽤,直接以扩展的形式结合到 php ⾥⾯,进⽽实现⾼效的⽹络服务。还有很多⽆限可能……
2020-08-25