上篇 「php回顧之io」 提到讀取檔案、網路通訊等操作,本質上是與 「流(stream)」 打交道。流機制是許多程式語言的重要機制,程式通過流可自由操作檔案、記憶體、網路等裝置的資料。
本文先簡要跟蹤php底層流的原理,再回到使用者態中流的使用。
我們知道php中的fopen
函式可以開啟本地檔案、url等並返回乙個控制代碼,fread
、fwrite
函式能對資源控制代碼進行讀寫,fclose
用於關閉資源。php如何做到使用一致api對不同資料來源進行操作?答案是php引入了「流」的概念,在底層對操作進行抽象,帶來的好處是上層可用同一套api。
為了理解php中的流,我們先追蹤php中fopen
函式呼叫過程。php的底層用c實現,閱讀文中的**需要一定的c語言基礎。如果不熟悉c語言,關注其思路即可。
使用者態的fopen
函式定義在ext/standard/file.c
檔案中,函式體如下:
php_named_function(php_if_fopen)
php_stream_to_zval(stream, return_value);
}複製**
php_named_function(php_if_fopen)
定義php中的fopen
函式(區別c中的fopen),有拓展開發基礎的應當對這種寫法熟悉。略過初始化等無關緊要的**,fopen
主要工作是獲取流物件(stream)並轉成php值型別(zval)返回。
zend_string **opened_path, php_stream_context *context streams_dc)
return null;
}} else
}// stream檢測等**
}複製**
if ((*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || (n == 4 && !memcmp("data:", path, 5))))
if (protocol)
protocol = null;
}efree(tmp);}}
/* todo: curl based streams probably support file:// properly */
if (!protocol || !strncasecmp(protocol, "file", n))
// 檢測遠端檔案等
}複製**
核心開發者在原始碼的readme.streams
檔案中解釋使用流的原因:讓拓展開發者能像普通檔案一樣運算元據。為達到這個目的,流操作的資源都是php_stream
物件。統一好資源介面後,php還定義了與檔案操作對應的一套流函式:
流函式的第乙個引數總是php_stream
物件,例如與fread
對應的php_stream_read
函式定義為:phpapi size_t php_stream_read(php_stream * stream, char * buf, size_t count)
。
更多關於底層流的操作可參考官方文件中開發者的「流」章節,本文不再深入。
讓我們回到php應用層面,即使用者態中的流。php的官方手冊有專門講解使用者態流的章節,並提供一系列以stream開頭的函式。由於fread/fputs等函式已經包含常見的流操作,stream開頭的函式主要分為三類:輔助的過濾器filter和上下文context,包裝器以及socket程式設計。網路程式設計將在後續的文章中講解,我們先關注包裝器。
開發者可以註冊流包裝器實現自定義協議,通過協議才能正常解析流的資料。比如我們為下面的小姐姐實現乙個專屬的協議secret://
:
class secretstream
function stream_read($count)
function stream_write($data)
function stream_tell()
function stream_eof()
function stream_close()
}複製**
使用自定義協議先要註冊,然後就可以正常使用了:
// 先註冊自定義協議
or die("failed to register protocol");
// 寫資料
$fp = fopen("secret://akari", "w+");
fwrite($fp, "ipz-985\n");
fwrite($fp, "ipx-021\n");
fwrite($fp, "ipz-933\n");
fclose($fp);
// 由於協議未實現seek功能,不能通過rewind讓檔案指標到頭部,需要重新開啟
$fp = fopen("secret://akari", "r");
while (!feof($fp))
fclose($fp);
複製**
通過簡單的**,我們安全的儲存了小姐姐的資料,也守護了小姐姐的秘密。其他人即使獲取到檔案內容,不通過我們的協議開啟也很難知道具體內容。有沒有感覺很不錯?小姐姐和你比心哦~
本文先回顧了php流底層的細節,再回到應用層中流的使用,並給出了乙個簡單的流包裝器示例(例子簡單,可用流章節中的php_user_filter來實現)。有興趣的讀者可以為下面的小姐姐建立自定義的協議,示例內容可以是:ssni-056、ssni-014、snis-662等。
本文感謝「微通廣州」的贊助。
感謝閱讀,敬請指正!
PHP基礎回顧
定義陣列 arr array 陣列賦值 arr i v arr array key v 定義鍵值key對應的值為v arr array v1,v2 迴圈訪問陣列 foreach arr as key value 去除兩側 左 右空格 trim ltrim rtrim str 獲取字串長度 strle...
PHP基礎之流程控制
php中的流程控制語句與其他程式語言類似,這裡就不多說了,直接通過 來看吧。1.if條件語句 if exp statement1 else statement2 很容易理解,如果exp為true,那麼執行statement1,否則執行statement2.此處exp為布林型別。當程式有多個分支的時候...
PHP學習記錄之流程控制
1 流程控制45 分支結構 if和switch 6 if語句 7 單分支8if condition 912 13 雙分支14 if condition 1518 else 1922 23 多分支24 if condition 2528 elseif condition 2932 elseif con...