php中有趣的流

來源:互聯網
上載者:User

有趣的流

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;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.