💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 15.4 操纵 # 操纵 5个静态包装器操作中的4个用来处理不是基于I/O的流资源操作. 你已经看到过它们并了解它们的原型; 现在我们看看varstream包装器框架中它们的实现: ## unlink 在你的wrapper\_ops结构体中增加下面的函数, 它可以让unlink()通过varstream包装器, 拥有和unset()一样的行为: ``` static int php_varstream_unlink(php_stream_wrapper *wrapper, char *filename, int options, php_stream_context *context TSRMLS_DC) { php_url *url; url = php_url_parse(filename); if (!url) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unexpected error parsing URL"); return -1; } if (!url->host || (url->host[0] == 0) || strcasecmp("var", url->scheme) != 0) { /* URL不合法 */ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid URL, must be in the form: " "var://variablename"); php_url_free(url); return -1; } /* 从符号表删除变量 */ //zend_hash_del(&EG(symbol_table), url->host, strlen(url->host) + 1); zend_delete_global_variable(url->host, strlen(url->host) + 1 TSRMLS_CC); php_url_free(url); return 0; } ``` 这个函数的编码量和php\_varstream\_opener差不多. 唯一的不同在于这里你需要传递变量名给zend\_hash\_del()去删除变量. > 译注: 译者的php-5.4.10环境中, 使用unlink()删除变量后, 在用户空间再次读取该变量名的值会导致core dump. 因此上面代码中译者进行了修正, 删除变量时使用了zend\_delete\_global\_variable(), 请读者参考阅读zend\_delete\_global\_variable()函数源代码, 考虑为什么直接用zend\_hash\_del()删除, 会导致core dump. 下面是译者测试用的用户空间代码: ``` <?php $fp = fopen('var://hello', 'r'); fwrite($fp, 'world'); var_dump($hello); unlink('var://hello'); $a = $hello; ``` 这个函数的代码量应该和php\_varstream\_opener差不多. 唯一的不同是这里是传递变量名给zend\_hash\_del()去删除变量. ## rename, mkdir, rmdir 为了一致性, 下面给出rename, mkdir, rmdir函数的实现: ``` static int php_varstream_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) { php_url *from, *to; zval **var; /* 来源URL解析 */ from = php_url_parse(url_from); if (!from) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unexpected error parsing source"); return -1; } /* 查找变量 */ if (zend_hash_find(&EG(symbol_table), from->host, strlen(from->host) + 1, (void**)&var) == FAILURE) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "$%s does not exist", from->host); php_url_free(from); return -1; } /* 目标URL解析 */ to = php_url_parse(url_to); if (!to) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unexpected error parsing dest"); php_url_free(from); return -1; } /* 变量的改名 */ Z_SET_REFCOUNT_PP(var, Z_REFCOUNT_PP(var) + 1); zend_hash_update(&EG(symbol_table), to->host, strlen(to->host) + 1, (void*)var, sizeof(zval*), NULL); zend_hash_del(&EG(symbol_table), from->host, strlen(from->host) + 1); php_url_free(from); php_url_free(to); return 0; } static int php_varstream_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) { php_url *url; /* URL解析 */ url = php_url_parse(url_from); if (!url) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unexpected error parsing URL"); return -1; } /* 检查变量是否存在 */ if (zend_hash_exists(&EG(symbol_table), url->host, strlen(url->host) + 1)) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "$%s already exists", url->host); php_url_free(url); return -1; } /* EG(uninitialized_zval_ptr)通常是IS_NULL的zval *, 引用计数无限大 */ zend_hash_add(&EG(symbol_table), url->host, strlen(url->host) + 1, (void*)&EG(uninitialized_zval_ptr), sizeof(zval*), NULL); php_url_free(url); return 0; } static int php_varstream_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) { /* 行为等价于unlink() */ wrapper->wops->unlink(wrapper, url, options, context TSRMLS_CC); } ``` ## links - [目录](preface.md) - 15.3 [实现一个包装器](15.3.html) - 15.5 [检查](15.5.html)