首頁 > 後端開發 > php教程 > PHP的Streams以及包裝器wrapper如何使用

PHP的Streams以及包裝器wrapper如何使用

php中世界最好的语言
發布: 2023-03-18 07:42:01
原創
1593 人瀏覽過

今天跟大家來說一下講述了PHP流Streams、包裝器wrapper概念與用法。總結給大家看一下。

我們知道,流Streams這個概念​​是在php4.3引進的,是對串流資料的抽象,用於統一資料操作,例如檔案資料、網路資料、壓縮資料等,以使可以共享相同套函數,php的檔案系統函數就是這樣的共享,例如file_get_contents()函數即可開啟本機檔案也可以存取url就是這一體現。簡單點講,流就是表現出串流資料行為的資源物件。

以線性方式進行讀寫,並且可以在流裡面任意位置進行搜尋。

流有點類似資料庫抽象層,在資料庫抽象層方面,不管使用何種資料庫,在抽象層之上都使用相同的方式操作數據,而流是對資料的抽象,它不管是本地文件還是遠端文件還是壓縮文件等等,只要來的是串流數據,那麼操作方式就是一樣的。

有了流這個概念就引申出了包裝器wrapper這個概念,每個流都對應一種包裝器,流是從統一操作這個角度產生的一個概念,而包裝器呢是從理解流資料內容出發產生的一個概念,也就是這個統一的操作方式怎麼操作或配置不同的內容;

這些內容都是以流的方式呈現,但內容規則是不一樣的,比如http協議傳來的數據是流的方式,但只有http包裝器才理解http協議傳來的數據的意思,可以這麼理解,流就是一根流水的管子,只不過它流出的是數據,包裝器就是套在流這根管子外層的一個解釋者,它理解流出的資料的意思,並且能操作它。

官方手冊說:「一個包裝器是告訴流怎麼處理特殊協議或編碼的附加代碼」明白這句話的意思了嗎?

包裝器可以嵌套,一個流外包裹了一個包裝器後,還可以在外層繼續包裹包裝器,這個時候裡層的包裝器相對於外層的包裝器充當流的角色
在php自身底層實現的c語言開發文件有這樣的解釋:

流API操作一對不同級別:在基本級別,api定義了php_stream物件表示串流資料來源,在稍微高一點的級別,api定義了php_stream_wrapper物件。

它包覆低一級的php_stream對象,以提供取回URL的內容和元資料、新增上下文參數的能力,調整包裝器行為;

每一種流打開後都可以應用任意數量的過濾器在上面,流資料會經過過濾器的處理,筆者認為過濾器這個詞用得有點不準確,有些誤導人。

從字面意思看好像是去掉一些數據的感覺,應該稱為數據調整器,因為它既可去掉一些數據,也可以添加,還可以修改,但歷史原因約定俗成,也就稱為過濾器了,大家心裡明白就好。

我們經常看到下面的詞,來解釋下他們的區別:

資源和數據:資源是比較宏觀的說法,通常包含數據,而數據是比較具象的說法,在開發程式的時候常說是數據,而在軟體規劃時說是資源,他們是近義詞,就像軟體設計和程式開發的區別一樣。

上下文與參數:上下文是比較宏觀的說法,常用在溝通上面,具體點講就是一次溝通本身的參數,而參數這個說法往往用在比較具體的事情上面,比如說函數

上面解釋了概念性的東西,下面來看看具體內容:

php支援的協定和包裝器請看這裡:http://php.net/manual/zh/wrappers .php:
(筆者註:原標題是:支援的協議和封裝協議,中文翻譯有點誤導,準確的講就是支持的協議和包裝器,從英文版面就很清楚)
默認的支持了一些協定和包裝器,請用stream_get_wrappers()函數查看.也可以自訂一個包裝器,用stream_wrapper_register()註冊
儘管RFC 3986裡面可以使用:做分割符,但php只允許://,所以url請使用"scheme://target"這樣的格式

file:// — 访问本地文件系统,在用文件系统函数时默认就使用该包装器
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
登入後複製

如何實作一個自訂的包裝器:

在用fopen、fwrite、fread、fgets、feof、rewind、 file_put_contents、file_get_contents等等檔案系統函數操作流時,資料是先傳給定義的包裝器類別對象,包裝器再去操作流。
如何實作一個自訂的流包裝器呢? php提供了一個類別原型,只是原型而已,不是介面也不是類,不能用來繼承:

streamWrapper {
/* 属性 */
public resource $context ;
/* 方法 */
__construct ( void )
__destruct ( void )
public bool dir_closedir ( void )
public bool dir_opendir ( string $path , int $options )
public string dir_readdir ( void )
public bool dir_rewinddir ( void )
public bool mkdir ( string $path , int $mode , int $options )
public bool rename ( string $path_from , string $path_to )
public bool rmdir ( string $path , int $options )
public resource stream_cast ( int $cast_as )
public void stream_close ( void )
public bool stream_eof ( void )
public bool stream_flush ( void )
public bool stream_lock ( int $operation )
public bool stream_metadata ( string $path , int $option , mixed $value )
public bool stream_open ( string $path , string $mode , int $options , string &$opened_path )
public string stream_read ( int $count )
public bool stream_seek ( int $offset , int $whence = SEEK_SET )
public bool stream_set_option ( int $option , int $arg1 , int $arg2 )
public array stream_stat ( void )
public int stream_tell ( void )
public bool stream_truncate ( int $new_size )
public int stream_write ( string $data )
public bool unlink ( string $path )
public array url_stat ( string $path , int $flags )
}
登入後複製

#

在这个原型里面定义的方法,根据自己需要去定义,并不要求全部实现,这就是为什么不定义成接口的原因,因为有些实现根本用不着某些方法,
这带来很多灵活性,比如包装器是不支持删除目录rmdir功能的,那么就不需要实现streamWrapper::rmdir
由于未实现它,如果用户在包装器上调用rmdir将有错误抛出,要自定义这个错误那么也可以实现它并在其内部抛出错误
streamWrapper也不是一个预定义类,测试class_exists("streamWrapper")就知道,它只是一个指导开发者的原型

官方手册提供了一个例子:http://php.net/manual/zh/stream.streamwrapper.example-1.php

本博客提供一个从drupal8系统中抽取修改过的包装器例子,请看drupal8源码分析关于流那一部分

流系列函数,官方手册:http://php.net/manual/zh/ref.stream.php

常用的函数如下:

stream_bucket_append函数:为队列添加数据 
stream_bucket_make_writeable函数:从操作的队列中返回一个数据对象
stream_bucket_new函数:为当前队列创建一个新的数据
stream_bucket_prepend函数:预备数据到队列 
stream_context_create函数:创建数据流上下文
stream_context_get_default函数:获取默认的数据流上下文
stream_context_get_options函数:获取数据流的设置
stream_context_set_option函数:对数据流、数据包或者上下文进行设置
stream_context_set_params函数:为数据流、数据包或者上下文设置参数
stream_copy_to_stream函数:在数据流之间进行复制操作
stream_filter_append函数:为数据流添加过滤器
stream_filter_prepend函数:为数据流预备添加过滤器
stream_filter_register函数:注册一个数据流的过滤器并作为PHP类执行
stream_filter_remove函数:从一个数据流中移除过滤器
stream_get_contents函数:读取数据流中的剩余数据到字符串
stream_get_filters函数:返回已经注册的数据流过滤器列表
stream_get_line函数:按照给定的定界符从数据流资源中获取行
stream_get_meta_data函数:从封装协议文件指针中获取报头/元数据
stream_get_transports函数:返回注册的Socket传输列表
stream_get_wrappers函数:返回注册的数据流列表
stream_register_wrapper函数:注册一个用PHP类实现的URL封装协议
stream_select函数:接收数据流数组并等待它们状态的改变
stream_set_blocking函数:将一个数据流设置为堵塞或者非堵塞状态
stream_set_timeout函数:对数据流进行超时设置
stream_set_write_buffer函数:为数据流设置缓冲区
stream_socket_accept函数:接受由函数stream_ socket_server()创建的Socket连接
stream_socket_client函数:打开网络或者UNIX主机的Socket连接
stream_socket_enable_crypto函数:为一个已经连接的Socket打开或者关闭数据加密
stream_socket_get_name函数:获取本地或者网络Socket的名称
stream_socket_pair函数:创建两个无区别的Socket数据流连接
stream_socket_recvfrom函数:从Socket获取数据,不管其连接与否
stream_socket_sendto函数:向Socket发送数据,不管其连接与否
stream_socket_server函数:创建一个网络或者UNIX Socket服务端
stream_wrapper_restore函数:恢复一个事先注销的数据包
stream_wrapper_unregister函数:注销一个URL地址包
登入後複製


相信看了这些案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

相关阅读:

php使用git部署环境

Git的一些使用案例

javascript数据类型和git使用代码详解

以上是PHP的Streams以及包裝器wrapper如何使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板