php中有趣的流
|
有趣的流
php常被提起的一个特性是流上下文. 这个可选的参数甚至在用户空间大多数流创建相关的函数中都可用, 它作为一个泛化的框架用于向给定包装器或流实现传入/传出额外的信息. 上下文 每个流的上下文包含两种内部消息类型. 首先最常用的是上下文选项. 这些值被安排在上下文中一个二维数组中, 通常用于改变流包装器的初始化行为. 还有一种则是上下文参数, 它对于包装器是未知的, 当前提供了一种方式用于在流包装层内部的事件通知. php_stream_context *php_stream_context_alloc(void); 通过这个API调用可以创建一个上下文, 它将分配一些存储空间并初始化用于保存上下文选项和参数的HashTable. 还会自动的注册为一个请求终止后将被清理的资源. 设置选项 设置上下文选项的内部API和用户空间的API是等同的:
int php_stream_context_set_option(php_stream_context *context,
const char *wrappername, const char *optionname,
zval *optionvalue);
下面是用户空间的原型:
bool stream_context_set_option(resource $context,
string $wrapper, string $optionname,
mixed $value);
它们的不同仅仅是用户空间和内部需要的数据类型不同.下面的例子就是使用这两个API调用, 通过内建包装器发起一个HTTP请求, 并通过一个上下文选项覆写了user_agent设置.
php_stream *php_varstream_get_homepage(const char *alt_user_agent TSRMLS_DC)
{
php_stream_context *context;
zval tmpval;
context = php_stream_context_alloc(TSRMLS_C);
ZVAL_STRING(&tmpval, alt_user_agent, 0);
php_stream_context_set_option(context, "http", "user_agent", &tmpval);
return php_stream_open_wrapper_ex("http://www.php.net", "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL, context);
}
译者使用的php-5.4.10中php_stream_context_alloc()增加了线程安全控制, 因此相应的对例子进行了修改, 请读者测试时注意. 这里要注意的是tmpval并没有分配任何持久性的存储空间, 它的字符串值是通过复制设置的. php_stream_context_set_option()会自动的对传入的zval内容进行一次拷贝. 取回选项 用于取回上下文选项的API调用正好是对应的设置API的镜像:
int php_stream_context_get_option(php_stream_context *context,
const char *wrappername, const char *optionname,
zval ***optionvalue);
回顾前面, 上下文选项存储在一个嵌套的HashTable中, 当从一个HashTable中取回值时, 一般的方法是传递一个指向zval **的指针给zend_hash_find(). 当然, 由于php_stream_context_get_option()是zend_hash_find()的一个特殊代理, 它们的语义是相同的. 下面是内建的http包装器使用php_stream_context_get_option()设置user_agent的简化版示例:
zval **ua_zval;
char *user_agent = "PHP/5.1.0";
if (context &&
php_stream_context_get_option(context, "http",
"user_agent", &ua_zval) == SUCCESS &&
Z_TYPE_PP(ua_zval) == IS_STRING) {
user_agent = Z_STRVAL_PP(ua_zval);
}
这种情况下, 非字符串值将会被丢弃, 因为对用户代理字符串而言, 数值是没有意义的. 其他的上下文选项, 比如max_redirects, 则需要数字值, 由于在字符串的zval中存储数字值并不通用, 所以需要执行一个类型转换以使设置合法. 不幸的是这些变量是上下文拥有的, 因此它们不能直接转换; 而需要首先进行隔离再进行转换, 最终如果需要还要进行销毁:
long max_redirects = 20;
zval **tmpzval;
if (context &&
php_stream_context_get_option(context, "http",
"max_redirects", &tmpzval) == SUCCESS) {
if (Z_TYPE_PP(tmpzval) == IS_LONG) {
max_redirects = Z_LVAL_PP(tmpzval);
} else {
zval copyval = **tmpzval;
zval_copy_ctor(?val);
convert_to_long(?val);
max_redirects = Z_LVAL(copyval);
zval_dtor(?val);
}
}
实际上, 在这个例子中, zval_dtor()并不是必须的. IS_LONG的变量并不需要zval容器之外的存储空间, 因此zval_dtor()实际上不会有真正的操作. 在这个例子中包含它是为了完整性考虑, 对于字符串, 数组, 对象, 资源以及未来可能的其他类型, 就需要这个调用了. 参数 虽然用户空间API中看起来参数和上下文选项是类似的, 但实际上在语言内部的php_stream_context结构体中它们被定义为不同的成员. 目前只支持一个上下文参数: 通知器. php_stream_context结构体中的这个元素可以指向下面的php_stream_notifier结构体:
typedef struct {
php_stream_notification_func func;
void (*dtor)(php_stream_notifier *notifier);
void *ptr;
int mask;
size_t progress, progress_max;
} php_stream_notifier;
(编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

