在描述之前,首先描述{资源}类型在核心中的结构://每个资源都是通过它来实现的。
typedef struct _zend_rsrc_list_entry
{
void *ptr;
int type;
int refcount;
}zend_rsrc_list_entry;
在现实世界中,我们经常需要操作一些不容易使用标量值的数据,比如文件的句柄,这只是C的指针。
#include
int main(void)
{
FILE *fd;
fd = fopen("/home/jdoe/.plan", "r");
fclose(fd);
return 0;
}
C语言中stdio文件描述符(file descriptor)它实际上是11个与每个打开的文件相匹配的变量FILE在程序和硬件交互通信中使用类型指针。我们可以用fopen函数打开文件获取句柄,然后只需将句柄传递给feof()、fread()、fwrite()、fclose()等函数,可以后续操作本文件。由于该数据不能直接用C语言中的标量数据表示,我们如何包装它以确保用户在PHP它也可以用于语言?这便是PHP中资源类型变量的作用!所以也是通过一个zval封装结构。
实现资源类型并不复杂。其值实只是一个整数,核心会根据这个整数值去类似资源池的地方寻找最终需要的数据。
资源类型变量的使用在实现中也有类型差异!为了区分不同类型的资源,如文件句柄和句柄mysql链接,我们需要给它不同的分类名称。首先,我们需要在程序中添加这个分类。这一步可以操作MINIT中来做:
#define PHP_SAMPLE_DESCRIPTOR_RES_NAME "山寨文件描述符"
static int le_sample_descriptor;
ZEND_MINIT_FUNCTION(sample)
{
le_sample_descriptor = zend_register_list_destructors_ex(NULL, NULL, PHP_SAMPLE_DESCRIPTOR_RES_NAME,module_number);
return SUCCESS;
}
//附加信息
#define register_list_destructors(ld, pld) zend_register_list_destructors((void (*)(void *))ld, (void (*)(void *))pld, module_number);
ZEND_API int zend_register_list_destructors(void (*ld)(void *), void (*pld)(void *), int module_number);
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, char *type_name, int module_number);
接下来,我们将定义它MINIT阶段的函数添加到扩展的module_entry里去,只需要把原来的"NULL, /* MINIT */"替换一行即可:
ZEND_MINIT(sample), /* MINIT */
ZEND_MINIT_FUNCTION()宏用来帮助我们定义它MINIT阶段函数。看到zend_register_list_destructors_ex()函数,你必须回忆一下是否有一个zend_register_list_destructors()函数呢?是的,确实有这样一个函数,它的参数比前者少了资源类别的名称。这两者有什么区别?
eaco $re_1;
//resource(4) of type (山寨版File句柄)
echo $re_2;
//resource(4) of type (Unknown)
为了创建资源,我们在上述核心注册了一种新的资源类型,下一步可以创建这种类型的资源变量。让我们简单地重新实现它fopen函数,现在叫sample_open:
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;
}
//将fp添加到资源池中,并标记为le_sample_descriptor类型的。
ZEND_REGISTER_RESOURCE(return_value,fp,le_sample_descriptor);
}
如果你读过前一章的所有知识,你应该能够猜出最后一行代码是什么。它创造了一个新的le_sample_descriptor这类资源的价值是fp,此外,它还将该资源添加到存储资源中HashTable该资源在其中对应的数字Key赋给return_value。
资源不局限于文件句柄。我们可以申请一个内存,它指向它的指针作为资源。因此,资源可以对应任何类型的数据。
世界上每件事都有喜怒哀乐,有生有灭。是时候讨论如何销毁资源了。最简单的就是模仿fclose写一个sample_close()函数在其中实现某种{资源:特别是指PHP释放以资源类型变量为代表的值}。
但是,如果用户端的脚本通过unset()函数如何释放资源类型的变量?他们不知道它的值最终对应一个FILE*指针啊,所以也无法使用fclose()函数释放它,这个FILE*句柄很可能一直存在于内存中,直到PHP程序挂掉,由OS来回收。但在一个普通的Web在环境中,我们的服务器将长期运行。
更多:php多条件查询语句代码PHP内核探索:资源resource类型
https://www.002pc.comhttps://www.002pc.com/phpbiancheng/1068.html
你可能感兴趣resource,PHP,核心、探索、类型、资源
No alive nodes found in your cluster
0踩
赏
0 赞