neu/pipe7

一个用于在PHP中轻松且一致地进行数据处理的开源库。

v1.1.0 2022-05-09 14:40 UTC

This package is auto-updated.

Last update: 2024-09-09 19:54:27 UTC


README

pipe7是一个基于Iterator的数据处理库。它旨在解决使用PHP内置的常规高阶函数(如array_filterarray_maparray_reduce)时可能遇到的一些问题。

PHP文档

PHPDocumentor生成的文档可以在以下链接找到:https://docs.pipe7.joern-neumeyer.de/

安装

composer require neu/pipe7

问题陈述

PHP已经提供了一些函数来对数组进行数据转换。然而,这些API并不一致,并且仅适用于数组。如果需要(或必须)使用GeneratorIterator,则不能使用这些内置函数。

此外,像array_map这样的函数会立即返回结果,即使可能对数组执行更多操作。它们可能会使用比必要的更多内存,因为中间数组在处理链的下一步中没有被使用。

解决方案

pipe7提供了一个一致且可预测的API来工作,因此代码更容易理解。它还支持Iterator作为数据源(这包括Generator)。

事实上,整个处理机制都是基于Iterator构建的。这允许pipe7在处理源数据结构的长时间转换链时具有很低的内存占用。这不仅有助于计算最终结果集(如转换为数组),而且还允许你仅在需要时触发计算,例如在foreach循环中。如果你只需要处理结果集中的前五个元素,pipe7将只请求足够从原始数据源获取这五个结果元素。因此,如果不需要,就不会将任何元素传递给回调(如array_map)。

还有...

有很多常见的操作你可能想在你的数据上执行(如平均计算、分组元素或将它们转换为字符串)。对于这些常见的用例,pipe7在MappersReducers类中提供了一系列的辅助函数。

要查看所有可用的辅助函数,请访问文档或使用phpDocumentor自行构建。

性能

pipe7是一个权衡。在CPU时间方面,它的性能不如标准数组函数。但这是重点。CPU时间被交换为内存效率。

此存储库包含一个基准测试,显示了pipe7与常规数组函数之间的性能差异。作为参考,数组函数被用作基准线。

表中给出的值仅是近似值。然而,很明显,pipe7在CPU效率上有所牺牲,但在内存效率上更加高效。正如所看到的,当使用Generator作为数据源时,RAM使用量特别低。

由于Generator(或通用的Iterator)与像array_map这样的函数不直接兼容,因此必须首先将其转换为数组,或者需要额外的数据处理机制。

因此,当pipe7可以与Generator一起使用时,它真正地大放异彩。

使用方法

创建一个新的 CollectionPipe

use Neu\Pipe7\CollectionPipe;

$data = [1,2,3];
$p = CollectionPipe::from($data);
// or with the shorthand
$p = pipe($data);

转换元素

$doubled = $p->map(function($x){ return $x * 2; })->toArray();
// if you're using php7.4 or later,
// better use arrow functions for more concise code
$doubled = $p->map(fn($x) => $x * 2)->toArray();

过滤元素

$even = $p->filter(fn($x) => $x % 2 === 0)->toArray();

组合元素

$total = $p->reduce(fn($carry, $x) => $carry + $x, 0);

如上所示,方法 mapfilter 总是返回一个新的 CollectionPipe,结果必须从其中收集(例如通过 toArray 方法)。也可以在 foreach 循环中迭代新的 CollectionPipe 实例。

相比之下,reduce 只有在其第三个参数设置为 true 并且 reduce 操作的 carry 是一个 Iterator 时才返回一个新的 CollectionPipe。如果第三个参数是 false 或未设置,则直接返回一个减少后的 array/Iterator。如果第三个参数是 true,并且减少的值不是一个 array/Iterator,将抛出一个 UnprocessableObject 异常。

有关更多信息,请参阅文档

有状态的运算符

有些操作不容易用一个单一函数表达。例如,可以是一个限制,在给定的管道中处理项目。因此,如果您需要实现这样的操作,请创建一个实现 interface Neu\Pipe7\StatefulOperatorclass

如果您想省去一些样板代码,考虑扩展 class Neu\Pipe7\CallableOperator。通过这样做,您将获得 __invoke 方法的实现,如果您的操作不需要任何特定的重置,还将获得 rewind 方法的空实现。

有状态的运算符可以作为参数传递给管道,就像您传递一个 Closure 一样。

传递的操作如何被评估?

根据特定管道需要完成的任务,了解管道的逻辑如何执行可能是很重要的。

映射器

签名:function(mixed $value, mixed $key, Neu\Pipe7\CollectionPipe $this)

如果您创建了一个管道,该管道应该转换传入的元素,那么当调用管道上的 current 方法时,将执行该逻辑。

过滤器

签名:function(mixed $value, mixed $key, Neu\Pipe7\CollectionPipe $this)

当调用管道上的 next 方法时,将调用过滤器,因为它们确定元素是否应该由管道发出。

减少器

签名:function(mixed #carry, mixed $value, mixed $key, Neu\Pipe7\CollectionPipe $this)

减少器的签名与映射器和过滤器不同,因为它们的任务是创建一个新值。因此,它们可以用来计算总和或类似的结果。

许可证

pipe7 在版本 3.0 或更新的 GNU Lesser General Public License 条件下提供使用