1. 云栖社区>
  2. PHP教程>
  3. 正文

php中有趣的流

作者:用户 来源:互联网 时间:2017-12-01 10:59:23

空间用户信息上下文包装

php中有趣的流 - 摘要: 本文讲的是php中有趣的流, 有趣的流 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;

 1/5    1 2 3 下一页 尾页

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索空间 , 用户 , 信息 , 上下文 包装 ,以便于您获取更多的相关知识。