PHP流Streams、包装器wrapper概念与用法实例详解

开发技术 作者: 2024-08-18 12:35:01
这篇文章主要介绍了PHP流Streams、包装器wrapper概念与用法,结合实例形式分析了php中流Streams与包装器wrapper的基本概念及使用方法,需要的朋友可以参考下

@H_502_0@本文实例讲述了PHP流Streams、包装器wrapper概念与用法。分享给大家供大家参考,具体如下:


@H_502_0@流Streams这个概念是在PHP4.3引进的,是对流式数据的抽象,用于统一数据操作,比如文件数据、网络数据、压缩数据等,以使可以共享同一套函数,PHP的文件系统函数就是这样的共享,比如file_get_contents()函数即可打开本地文件也可以访问url就是这一体现。简单点讲,流就是表现出流式数据行为的资源对象。


@H_502_0@以线性方式进行读写,并可以在流里面任意位置进行搜索。


@H_502_0@流有点类似数据库抽象层,在数据库抽象层方面,不管使用何种数据库,在抽象层之上都使用相同的方式操作数据,而流是对数据的抽象,它不管是本地文件还是远程文件还是压缩文件等等,只要来的是流式数据,那么操作方式就是一样的。


@H_502_0@有了流这个概念就引申出了包装器wrapper这个概念,每个流都对应一种包装器,流是从统一操作这个角度产生的一个概念,而包装器呢是从理解流数据内容出发产生的一个概念,也就是这个统一的操作方式怎么操作或配置不同的内容;


@H_502_0@这些内容都是以流的方式呈现,但内容规则是不一样的,比如http协议传来的数据是流的方式,但只有http包装器才理解http协议传来的数据的意思,可以这么理解,流就是一根流水的管子,只不过它流出的是数据,包装器就是套在流这根管子外层的一个解释者,它理解流出的数据的意思,并能操作它。


@H_502_0@官方手册说:“一个包装器是告诉流怎么处理特殊协议或编码的附加代码”明白这句话的意思了吗?


@H_502_0@包装器可以嵌套,一个流外面包裹了一个包装器后,还可以在外层继续包裹包装器,这个时候里层的包装器相对于外层的包装器充当流的角色
在PHP自身底层实现的c语言开发文档有这样的解释:


@H_502_0@流API操作一对不同级别:在基本级别,api定义了PHP_stream对象表示流式数据源,在稍微高一点的级别,api定义了PHP_streamwrapper对象。


@H
502_0@它包裹低一级别的PHP_stream对象,以提供取回URL的内容和元数据、添加上下文参数的能力,调整包装器行为;


@H_502_0@每一种流打开后都可以应用任意数量的过滤器在上面,流数据会经过过滤器的处理,笔者认为过滤器这个词用得有点不准确,有些误导人。


@H_502_0@从字面意思看好像是去掉一些数据的感觉,应该称为数据调整器,因为它既可去掉一些数据,也可以添加,还可以修改,但历史原因约定俗成,也就称为过滤器了,大家心里明白就好。


@H_5020@我们经常看到下面的词,来解释下他们的区别:


@H
5020@资源和数据:资源是比较宏观的说法,通常包含数据,而数据是比较具象的说法,在开发程序的时候经常说是数据,而在软件规划时说是资源,他们是近义词,就像软件设计和程序开发的区别一样。


@H
502_0@上下文和参数:上下文是比较宏观的说法,经常用在沟通上面,具体点讲就是一次沟通本身的参数,而参数这个说法往往用在比较具体的事情上面,比如说函数


@H_502_0@上面解释了概念性的东西,下面来看看具体内容:


@H_502_0@

PHP支持的协议和包装器请看这里:

http://php.net/manual/zh/wrappers.php:
(笔者注:原标题是:支持的协议和封装协议,中文翻译有点误导,准确的讲就是支持的协议和包装器,从英文版面就很清楚)
默认的支持了一些协议和包装器,请用stream_get_wrappers()函数查看.也可以自定义一个包装器,用stream_wrapper_register()注册
尽管RFC 3986里面可以使用:做分割符,但PHP只允许://,所以url请使用"scheme://target"这样的格式


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


@H_502_0@

如何实现一个自定义的包装器:


@H_502_0@在用fopen、fwrite、fread、fgets、feof、rewind、file_put_contents、file_get_contents等等文件系统函数操作流时,数据是先传给定义的包装器类对象,包装器再去操作流。
如何实现一个自定义的流包装器呢?PHP提供了一个类原型,只是原型而已,不是接口也不是类,不能用于继承:


<div class="jb51code">
<pre class="brush: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 streamlock ( 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 )
}

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

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

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

@H_502_0@

流系列函数

,官方手册:http://php.net/manual/zh/ref.stream.php

@H_502_0@常用的函数如下:

@H_502_0@ @H_502_0@

一个过滤器的列子及解释:

@H_502_0@官网相关链接:

@H_502_0@用户过滤器基类:http://php.net/manual/zh/class.php-user-filter.php 过滤器注册:http://php.net/manual/zh/function.stream-filter-register.php

data = strtoupper($bucket->data); $consumed += $bucket->datalen; stream_bucket_append($out,$bucket); //将修改后的数据送到输出的地方 } return PSFS_PASS_ON; } } /* 注册过滤器到PHP */ stream_filter_register("strtoupper","strtoupper_filter") or die("Failed to register filter"); $fp = fopen("foo-bar.txt","w"); /* 应用过滤器到一个流 */ stream_filter_append($fp,"strtoupper"); fwrite($fp,"Line1\n"); fwrite($fp,"Word - 2\n"); fwrite($fp,"Easy As 123\n"); fclose($fp); //读取并显示内容 将全部变为大写 readfile("foo-bar.txt"); ?>
@H_502_0@更多关于PHP相关内容感兴趣的读者可查看本站专题:《》、《》、《》、《》、《》、《》及《PHP常见数据库操作技巧汇总》

@H_502_0@希望本文所述对大家PHP程序设计有所帮助。

原创声明
本站部分文章基于互联网的整理,我们会把真正“有用/优质”的文章整理提供给各位开发者。本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
本文链接:http://www.jiecseo.com/news/show_64364.html
PHP Streams 包装器 wrapper

本站采用系统自动发货方式,付款后即出现下载入口,如有疑问请咨询在线客服!

售后时间:早10点 - 晚11:30点

咨询售后客服

推荐精华