controlaltsoft / hoa-stream
为添加php8支持而 fork 的 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
Replaces
- hoa/stream: 1.17.*
This package is not auto-updated.
Last update: 2024-09-29 07:06:30 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,当流的内容类型已知时,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。
获取帮助
主要有两种获取帮助的方式
- 在
#hoaprojectIRC 频道中, - 在 users.hoa-project.net 的论坛上。
贡献
你想贡献吗?谢谢!一个详细的贡献指南解释了你需要知道的一切。
许可证
Hoa遵循新BSD许可证(BSD-3-Clause)。请查阅LICENSE获取详细信息。
相关项目
以下项目正在使用这个库
- Marvirc,一个简单、高度模块化且速度极快的IRC机器人,
- WellCommerce,基于Symfony 3全栈框架的现代电子商务引擎,
- 当然还有许多Hoa库。