talesoft / tale-collection
Requires
- php: >=7.1.0
- talesoft/tale-iterator: ^0.1.1
Requires (Dev)
- phpbench/phpbench: @dev
- talesoft/tale-dev-tool: ^0.2.5
This package is auto-updated.
Last update: 2024-09-11 15:33:50 UTC
README
Tale Collection
什么是Tale Collection?
Tale Collection 是一个针对PHP的基于迭代器的Collection实现。
它包含一个通用的Collection类,该类可以很好地处理链式迭代,并提供了Map和Set实现,API稳定。
安装
composer require talesoft/tale-collection
用法
Collection
签名
Tale\collection(iterable $iterable): Tale\CollectionInterface //or new Tale\Collection(iterable $iterable)
示例
use function Tale\collection; $collection = collection(['a', 'b', 'c', 'd'])) ->filter(function (string $char) { return $char !== 'b'; }) ->map(function (string $char) { return strtoupper($char) }) ->flip(); var_dump($collection['c']); //int(2) var_dump($collection->toArray()); /* array(3) { 'a' => int(0) 'c' => int(2) 'd' => int(3) } */
如上所述,它高度基于迭代器,因此除非实际访问数据,否则许多堆叠操作永远不会将任何内容转换为实际的数组。
让我们演示一下!
use function Tale\collection; funuction generateAtoZ() { //Imagine this is some hard work yield from range('a', 'z'); } $collection = collection(generateAtoZ()) //We filter all a-s ->filter(function (string $char) { return $char !== 'a'; }) //We also chain a normal SPL RegexIterator and drop all i to z-s ->chain(\RegexIterator::class, '/[^i-z]/') //Uppercase all characters ->map(function (string $char) { return strtoupper($char); }) //Flip the keys and values ->flip() //Drop characters with the index 3 (this will be 'C') ->filter(function (int $index) { return $index !== 2; }) //Flip again ->flip() //Only yield the values (array_values, basically) ->getValues(); //This right below is the _first_ part where generateAtoZ will //actually be triggered at all! Until then we basically did nothing //except for chaining some iterators var_dump($collection[2]); //string(1) "E" //Notice how it's E, because we dropped A and C var_dump($collection->toArray()); /* array(6) { [0] => string(1) "B" [1] => string(1) "D" [2] => string(1) "E" [3] => string(1) "F" [4] => string(1) "G" [5] => string(1) "H" } */
大多数 Tale Collection的方法会返回另一个Collection。Collection不仅包含数组,还可以包含一个可迭代对象。可迭代对象会通过您使用的几乎所有方法传递,只有在您访问键或将其转换为数组时才会懒加载。
这为深度修改可迭代值提供了可能,而无需在所有地方创建数组副本。
实际上,上述示例中除了toAray()
之外,没有调用任何方法触发了generateAtoZ()
生成器,甚至包括getValues()
或flip()
。它们都返回包含嵌套特定迭代器的集合。
这还导致了一些很好的副作用,比如flip()
不会覆盖值。
想象一下,我们想在翻转数组时处理键,而不会覆盖其值(非常节省内存)
use function Tale\collection; $values = collection(['a' => 2, 'b' => 2, 'c' => 3]) ->flip() ->map(function (string $key) { return strtoupper($key); }) ->flip(); var_dump($values->toArray()); /* array(3) { 'A' => int(2) 'B' => int(2) 'C' => int(3) } */
要了解发生了什么,让我们看看原生的PHP等效代码
use function Tale\collection; $values = array_flip(['a' => 2, 'b' => 2, 'c' => 3]); //Here our values are lost already, it will result in // [2 => 'b', 3 => 'c'], as keys are unique $values = array_map(function (string $key) { return strtoupper($key); }, $values); $values = array_flip(['a' => 2, 'b' => 2, 'c' => 3]); var_dump($values); /* array(2) { ["B"]=> int(2) ["C"]=> int(3) } */
由于迭代器的工作方式,值在检索最终结果之前永远不会被简化为实际的数组,重复键在迭代过程中不会有问题,并且始终可用,直到可迭代对象在内部转换为数组。
特殊化的集合
以下所有集合都使用与上述讨论的集合类相同的迭代器机制。实际上,它们都实现了Tale\CollectionInterface
,并使用一个公共基类Tale\AbstractCollection
来定义它们的大部分API。
Set
Set类是一组值的抽象,其中键不重要。Set的键将得到管理,并且始终保持顺序。
值将是唯一的。如果值已存在于Set中,则在使用add
时不会再次添加。
内容通过以下API管理
Set->has($item)
检查集合是否包含特定项
Set->add($item)
向集合添加新项
Set->remove($item)
从集合中删除项
use function Tale\set; $existingObject = new SomeClass(); $set = set(); $set->add(new SomeOtherClass()); var_dump($set->has($existingObject)); //bool(true) var_dump($set->toArray()); /* array(3) { 0 => object(SomeOtherClass)#1 (0) {} 1 => object(SomeClass)#2 (0) {} } */
常见用例
元素上的CSS类集合
use function Tale\set; $classList = set(['btn']); if ($primary) { $classList->add('btn-primary'); } if ($block) { $classList->add('btn-block'); } if ($classList->has('primary') { echo "This is a primary button!\n"; } echo "<button class=\"{$classList->join(' ')}\">My button!</button>";
Map
Map是一种数据结构,允许使用除了字符串和整数以外的键。由于PHP引擎的限制,您不能通过数组访问访问复杂键([$obj]
)。
以下API管理Map
Map->get($key)
检索特定键的值
Map->set($key, $value)
为特定键设置值
Map->has($key)
检查特定键是否存在
Map->remove($key)
从Map中删除具有特定键的值
use function Tale\map; $key1 = new Key1(); $key2 = new Key2(); $map = map(); $map->set($key1, 'value 1'); $map->set($key2, 'value 2'); var_dump($map->toArray()); /* array(3) { 0 => array(2) { 0 => object(SomeOtherClass)#1 (0) {} 1 => string(7) "value 1" } 1 => array(2) { 0 => object(SomeClass)#2 (0) {} 1 => string(7) "value 2" } } */
常见用例
对象的元数据存储
use function Tale\map; $metadata = map(); $b = new B(); $objects = [ new A(), $b, new C(), new D() ]; foreach ($objects as $obj) { $metadata->set($obj, getMetadataForObject($obj)); } //[...] if ($metadata->has($b)) { $bMetadata = $metadata->get($b); //$bMetadata is now the metadata for the $b instance }
待办事项:更多文档。