PHP回顧之流

2021-09-11 09:43:52 字數 3000 閱讀 4268

上篇 「php回顧之io」 提到讀取檔案、網路通訊等操作,本質上是與 「流(stream)」 打交道。流機制是許多程式語言的重要機制,程式通過流可自由操作檔案、記憶體、網路等裝置的資料。

本文先簡要跟蹤php底層流的原理,再回到使用者態中流的使用。

我們知道php中的fopen函式可以開啟本地檔案、url等並返回乙個控制代碼,freadfwrite函式能對資源控制代碼進行讀寫,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...