hoa / stream
Hoa\Stream 库。
Requires
- hoa/consistency: ~1.0
- hoa/event: ~1.0
- hoa/exception: ~1.0
- hoa/protocol: ~1.0
Requires (Dev)
- hoa/test: ~2.0
This package is auto-updated.
Last update: 2021-09-20 08:32:01 UTC
README
Hoa 是一套 模块化、可扩展 和 结构化 的 PHP 库。
此外,Hoa 致力于成为工业界和研究界之间的桥梁。
Hoa\Stream
此库是 PHP 流的高级抽象。它包括
- 流操作:打开、关闭、自动关闭、超时、阻塞模式、缓冲区大小、元数据等
- 流通知:根据流包装器的不同,支持的监听器如下:
authrequire
、authresult
、complete
、connect
、failure
、mimetype
、progress
、redirect
、resolve
和size
- 上下文:允许向流包装器传递选项和参数,例如 HTTP 头
- 过滤器:一个位于流源和目的地的函数,例如用于加密/解密数据,或用于更高级的技巧,如仪表化
- 包装器:声明用户定义的协议,这些协议将由 PHP 标准库自然处理(例如
fopen
、stream_get_contents
等) - 接口:每个接口代表流可以提供的功能
此库是其他几个库的基础,例如 Hoa\File
或 Hoa\Socket
(以及 Hoa\Websocket
)
了解更多.
安装
使用 Composer,要将此库包含在依赖项中,您需要要求 hoa/stream
$ composer require hoa/stream '~1.0'
有关更多安装程序,请参阅 源页面。
测试
在运行测试套件之前,必须安装开发依赖项
$ composer install
然后,要运行所有测试套件
$ vendor/bin/hoa test:run
有关更多信息,请参阅 贡献者指南。
快速使用
作为一个快速概述,我们建议您了解 Hoa\Stream
在接口方面的提供,即流功能。这是本库最重要的部分。然后,如何定义流,接着是流上下文的定义。事件、监听器和通知将在下一节中详细说明。最后,包装器和过滤器将在最后一节中详细说明。
接口,即流功能
本库定义了几个表示重要流功能的接口。这在设计一个与流一起工作的函数或库时非常有用。它确保流具有类型并提供某些功能。接口在 Hoa\Stream\IStream
命名空间中声明。
In
,用于从流中读取,提供read
、readInteger
、readLine
、readAll
、eof
等。Out
,用于向流写入,提供write
、writeArray
、writeLine
、truncate
等。Bufferable
,对于至少有一个内部缓存的流,提供newBuffer
、flush
、getBufferLevel
等。Touchable
,对于“可触摸”的流,提供touch
、copy
、move
、delete
、changeGroup
等。Lockable
,用于锁定流,提供lock
和代表不同类型锁的几个常量,如LOCK_SHARED
、LOCK_EXCLUSIVE
、LOCK_NO_BLOCK
等。Pathable
,对于基于路径的流,提供getBasename
和getDirname
。Pointable
,用于移动流内部指针(如果有的话),提供rewind
、seek
和tell
。Statable
,用于获取有关流的统计信息,提供getSize
、getStatistics
、getATime
、getCTime
、isReadable
等。Structural
,对于结构化流,即像树一样的流,提供selectRoot
、selectAnyElements
、selectElements
、selectAdjacentSiblingElement
、querySelector
等。
因此,如果只需要从流中读取,它将使用 Hoa\Stream\IStream\In
类型化流。它还允许实现者选择其流将提供哪些或哪些不提供的能力。
最后,最高的接口是 Stream
,定义了 getStream
方法,就这些。这是最不确定的流。所有功能都必须扩展此接口。
定义一个具体的流
主要的 Hoa\Stream\Stream
类是抽象的。用户留下两个方法实现:_open
和 _close
,分别用于打开特定的流和关闭此特定的流,例如。
class BasicFile extends Hoa\Stream\Stream { protected function &_open($streamName, Hoa\Stream\Context $context = null) { if (null === $context) { $out = fopen($streamName, 'rb'); } else { $out = fopen($streamName, 'rb', false, $context->getContext()); } return $out; } protected function _close() { return fclose($this->getStream()); } }
然后,最常用的用法将是
$file = new BasicFile('/path/to/file');
这就是全部。这个流还没有能力。让我们实现 In
能力
class BasicFile extends Hoa\Stream\Stream implements Hoa\Stream\IStream\In { // … public function read($length) { return fread($this->getStream(), max(1, $length)); } // … }
其他方法留作读者练习。因此,我们现在能够
$chunk = $file->read(42);
Stream
能力已由 Hoa\Stream\Stream
类实现。
上下文流
上下文由 Hoa\Stream\Context
类表示。它表示一组选项和参数,用于流。例如,请参阅 http:// 的选项和参数 作为可能的示例。多亏了上下文,可以添加HTTP头信息,或指定代理、最大重定向次数等。所有这些信息都是流的选项/参数。
要使用它们,首先让我们定义上下文
$contextId = 'my_http_context'; $context = Hoa\Stream\Context::getInstance($contextId); $context->setOptions([ // … ]);
因此,我们可以要求流根据所选的上下文ID使用此上下文,如下所示
$basicFile = new BasicFile('/path/to/file', $contextId);
对于流实现者,Hoa\Stream\Context
类上的 getOptions
和 getParameters
方法将分别用于检索选项和参数,并根据它们执行操作。
“选项”和“参数”的概念由PHP本身定义。
事件、监听器和通知
流有一些事件,以及几个监听器。到目前为止,监听器主要代表“流通知”。
已注册了2个事件:hoa://Event/Stream/<streamName>
和 hoa://Event/Stream/<streamName>:close-before
。因此,例如,在 /path/to/file
流关闭之前执行一个函数,可以这样编写
Hoa\Event\Event::getEvent('hoa://Event/Stream//path/to/file:close-before')->attach( function (Hoa\Event\Bucket $bucket) { // do something! } );
请记住,流不一定是文件。它可以是一个套接字、WebSocket、字符串缓冲区,或者是您定义的任何流……因此,该事件可以根据不同的场景以非常不同的方式使用,例如记录日志、关闭相关资源、触发另一个事件……没有规则。观察到的流仍然是打开的,理论上仍然可以继续使用。
当调用 Hoa\Stream\Stream::close
方法时,会触发此事件。
现在让我们谈谈监听器。要注册一个监听器,我们必须创建一个流实例,但不打开它。这个动作称为“延迟打开”。我们可以通过默认的 Hoa\Stream\Stream
构造函数的第三个参数控制打开时间;设置为 true
以延迟打开,如下所示
$file = new BasicFile('/path/to/file', null, true); // do something $file->open();
将第二个参数传递为 null
表示:没有上下文。请注意,我们必须手动调用 open
方法来打开流。在流实例化和流打开之间,我们可以添加新的监听器。
根据流实现的不同,将触发不同的监听器。在Hoa中,使用“监听器”一词,但PHP——在流的环境中——将它们称为通知。让我们以HTTP流为例
$basic = new BasicFile( 'https://hoa-project.net/', // stream name null, // context ID true // defere opening ); $basic->on( 'connect', function (Hoa\Event\Bucket $bucket) { echo 'Connected', "\n"; } ); $basic->on( 'redirect', function (Hoa\Event\Bucket $bucket) { echo 'Redirection to ', $bucket->getData()['message'], "\n"; } ); $basic->on( 'mimetype', function (Hoa\Event\Bucket $bucket) { echo 'MIME-Type is ', $bucket->getData()['message'], "\n"; } ); $basic->on( 'size', function (Hoa\Event\Bucket $bucket) { echo 'Size is ', $bucket->getData()['max'], "\n"; } ); $basic->on( 'progress', function (Hoa\Event\Bucket $bucket) { echo 'Progressed, ', $bucket->getData()['transferred'], ' bytes downloaded', "\n"; } ); // Then open. $basic->open();
您可能会看到如下内容
Connected
MIME-Type is text/html; charset=UTF-8
Redirection to /En/
Connected
MIME-Type is text/html; charset=UTF-8
Progressed, … bytes downloaded
Progressed, … bytes downloaded
监听器的完整列表如下
authrequire
,当需要认证时,authresult
,当认证结果已知时,complete
,当流完成时(这里的含义可能很大),connect
,当流连接时(这里的含义可能很大),failure
,当发生意外情况时,mimetype
,当流的MIME类型已知时,progress
,当有显著的进度时,redirect
,当流被重定向到另一个流时,resolve
,当流被解析时(这里的含义可能很大),size
,当流的尺寸已知时。
所有监听器桶数据是一个包含以下对的数组
code
,是STREAM_NOTIFY_*
常量之一,基本上是监听器名称(见文档),severity
,是STREAM_NOTIFY_SEVERITY_*
常量之一STREAM_NOTIFY_SEVERITY_INFO
,普通,非错误相关,通知,STREAM_NOTIFY_SEVERITY_WARN
,非关键错误条件,处理可以继续,STREAM_NOTIFY_SEVERITY_ERR
,发生了关键错误,处理无法继续。
message
,包含最有用的信息的字符串,transferred
,已传输的字节数,max
,要传输的总字节数。
流实现者可以为监听器添加更多内容。请参阅Hoa\Event
库。并非所有类型的流都会触发所有监听器。
包装器
流包装器允许声明方案,如 hoa://
或 fortune://
。您可以想象添加您最喜欢的在线存储,cloud://
。任何流包装器都可以与原生标准PHP函数一起使用,如 fopen
、file_get_contents
、mkdir
、touch
等。用户将不会感觉到。
Hoa\Stream\Wrapper\Wrapper
类包含所有用于 register
、unregister
和 restore
包装器的函数。isRegistered
和 getRegistered
方法也非常有用。包装器由一个类表示
Hoa\Stream\Wrapper\Wrapper::register('tmp', Tmp::class);
包装器必须实现 Hoa\Stream\Wrapper\IWrapper\IWrapper
接口。它是同一命名空间中两个其他接口的组合:Stream
和 File
。
Stream接口需要实现与流相关的几个方法,例如
stream_open
,stream_close
,stream_cast
,stream_eof
,stream_flush
,stream_lock
,stream_metadata
,stream_read
,stream_write
,stream_seek
,stream_tell
,stream_stat
,- 等等。
API提供了所有需要的信息。
File接口需要实现其他与作为文件操作相关的流方法,例如
mkdir
,dir_opendir
,dir_closedir
,dir_readdir
,rename
,unlink
,- 等等。
一个实现示例是Hoa\Protocol库中的hoa://方案。它不依赖于这个库以避免依赖,但代码可能有所帮助。
过滤器
流就像一个管道,有输入和输出。现在可以将这个管道切分成两部分,并插入一小部分:一个过滤器。有三种类型的过滤器,由Hoa\Stream\Filter\Filter
类上的常量标识
Filter::READ
当过滤器应用于读取操作时Filter::WRITE
当过滤器应用于写入操作时Filter::READ_AND_WRITE
当两者都应用时
这个类允许注册或删除过滤器。过滤器采用一个扩展自Hoa\Stream\Filter\Basic
过滤器的类和一个相关的名称的形式。这不是强制性的,但强烈推荐。
一旦注册了过滤器,我们就可以使用它的名称,通过使用append
或prepend
方法将其应用于流。你可能已经猜到,可以在流上应用多个过滤器,并按特定顺序应用,例如“解密”、“解压缩”、“转换成…”。在这种情况下,顺序很重要。
最后,我们像往常一样使用流。流不一定是Hoa\Stream
的实例,它可以是任何PHP流资源。传递一个Hoa\Stream
实例将明显展开到其底层的PHP流资源。
让我们实现一个将流内容转换为大写的过滤器。我们首先定义我们的过滤器
class ToUpper extends Hoa\Stream\Filter\Basic { public function filter($in, $out, &$consumed, $closing) { $iBucket = new Hoa\Stream\Bucket($in); $oBucket = new Hoa\Stream\Bucket($out); while (false === $iBucket->eob()) { $consumed += $iBucket->getLength(); $iBucket->setData(strtoupper($iBucket->getData())); $oBucket->append($iBucket); } unset($iBucket); unset($oBucket); return parent::PASS_ON; } }
很好。现在让我们将我们的过滤器注册为一个特定的名称
$filterName = 'toupper'; Hoa\Stream\Filter::register($filterName, ToUpper::class);
然后,我们必须将过滤器应用于特定的流,所以让我们打开一个流,并附加过滤器
$file = new Hoa\File\Read(__FILE__); Hoa\Stream\Filter::append($file, $filterName, Hoa\Stream\Filter::READ);
此过滤器仅应用于读取操作。因此,当我们读取流时将看到其效果,让我们来试试
echo $file->readAll();
你将看到所有内容都是ASCII大写。
过滤器是一个低级流API。它与各种流集成。这是一个非常强大的工具。我们提到了一些用法,如解密、转换、解压缩等。实际上,PHP附带了一些标准过滤器,如:string.toupper
、string.tolower
、dechunk
、zlib.*
、bzip2.*
、convert.iconv.*
等。Hoa\Stream\Filter\Filter::getRegistered
方法将提供所有注册过滤器的列表。
Hoa\Stream\Filter\LateComputed
类是一个特殊的过滤器。它在流达到其末尾时调用其公共的compute
方法。因此,通过扩展此过滤器,你可以重写compute
方法并工作在_buffer
属性上。此缓冲区包含流的全部内容。这真的是一个缓冲区。为什么会很有用?例如,如果你正在读取PHP文件,你可以使用解析器(例如)实时转换源代码并重写文件的部分。这种技术特别适用于对代码进行仪器化(添加一些探测器)。
也可以通过包装器自动应用过滤器。例如,instrument://
包装器可以预先将过滤器附加到使用stream_open
方法(来自Hoa\Stream\Wrapper\IWrapper\Stream
接口)打开的流上。
可能性是无穷无尽的。
其他操作
还有更多内容需要介绍。 Hoa\Stream
支持组合流(使用 Hoa\Stream\Composite
抽象类),即嵌入其他流的流,例如 Hoa\Xml
库。XML 流从另一个内部流(文件、套接字或其他内容)读取和写入。 Hoa\Stringbuffer
库 允许使用流 API 操作字符串,因此流内容被写入磁盘。与您可能猜想的 Hoa\File
不同,流的特性并不相同。
文档
Hoa\Stream
的黑客手册 包含有关如何使用此库及其工作原理的详细信息。
要本地生成文档,请执行以下命令
$ composer require --dev hoa/devtools $ vendor/bin/hoa devtools:documentation --open
更多文档可以在项目的网站上找到: hoa-project.net。
获取帮助
获取帮助主要有两种方式
- 在
#hoaproject
IRC 频道中, - 在 users.hoa-project.net 论坛上。
贡献
你想贡献力量吗?谢谢!详细的 贡献指南 解释了你需要知道的一切。
许可证
Hoa 采用新的 BSD 许可证(BSD-3-Clause)。请参阅 LICENSE
了解详细信息。
相关项目
以下项目正在使用此库
- Marvirc,一个简单、极度模块化和极快的 IRC 机器人,
- WellCommerce,基于 Symfony 3 全栈框架的现代电子商务引擎,
- 当然还有许多 Hoa 库。