程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> 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. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved