集合 collection

Testing Is Documentation

tests/Collection/CollectionTest.php集合 collection - 图1

集合 collection 提供了一些实用方法,数据库查询的数据列表也会转换为集合数据类型。

Uses

  1. <?php
  2. use JsonSerializable;
  3. use Leevel\Collection\Collection;
  4. use Leevel\Support\IArray;
  5. use Leevel\Support\IJson;
  6. use stdClass;

基本使用

集合实现了 \IteratorAggregate 可以像普通数组一样遍历,也实现了 \ArrayAccess 接口,可以当做普通数组一样使用。

  1. public function testBaseUse(): void
  2. {
  3. $data = [
  4. 'hello', 'world', 'foo', 'bar',
  5. ];
  6. $collection = new Collection($data);
  7. foreach ($collection as $key => $val) {
  8. switch ($key) {
  9. case 0:
  10. $this->assertSame($val, 'hello');
  11. break;
  12. case 1:
  13. $this->assertSame($val, 'world');
  14. break;
  15. case 2:
  16. $this->assertSame($val, 'foo');
  17. break;
  18. case 3:
  19. $this->assertSame($val, 'bar');
  20. break;
  21. }
  22. }
  23. $this->assertSame($collection[0], 'hello');
  24. $this->assertSame($collection[1], 'world');
  25. $this->assertSame($collection[2], 'foo');
  26. $this->assertSame($collection[3], 'bar');
  27. $this->assertTrue(isset($collection[0]));
  28. $this->assertTrue(isset($collection[1]));
  29. $this->assertTrue(isset($collection[2]));
  30. $this->assertTrue(isset($collection[3]));
  31. $this->assertFalse(isset($collection[4]));
  32. }

静态方法 make 创建集合

可以使用 make 方法创建一个集合对象。

  1. public function testMake(): void
  2. {
  3. $data = [
  4. 'hello', 'world', 'foo', 'bar',
  5. ];
  6. $collection = Collection::make($data);
  7. foreach ($collection as $key => $val) {
  8. switch ($key) {
  9. case 0:
  10. $this->assertSame($val, 'hello');
  11. break;
  12. case 1:
  13. $this->assertSame($val, 'world');
  14. break;
  15. case 2:
  16. $this->assertSame($val, 'foo');
  17. break;
  18. case 3:
  19. $this->assertSame($val, 'bar');
  20. break;
  21. }
  22. }
  23. $this->assertSame($collection[0], 'hello');
  24. $this->assertSame($collection[1], 'world');
  25. $this->assertSame($collection[2], 'foo');
  26. $this->assertSame($collection[3], 'bar');
  27. $this->assertTrue(isset($collection[0]));
  28. $this->assertTrue(isset($collection[1]));
  29. $this->assertTrue(isset($collection[2]));
  30. $this->assertTrue(isset($collection[3]));
  31. $this->assertFalse(isset($collection[4]));
  32. }

集合支持迭代器

集合 collection 是一个标准的迭代器,支持迭代器的用法。

  1. public function testIterator(): void
  2. {
  3. $data = [
  4. 'hello', 'world', 'foo', 'bar',
  5. ];
  6. $collection = new Collection($data);
  7. $this->assertSame('hello', $collection->current());
  8. $this->assertSame(0, $collection->key());
  9. $this->assertNull($collection->next());
  10. $this->assertSame('world', $collection->current());
  11. $this->assertSame(1, $collection->key());
  12. $this->assertNull($collection->next());
  13. $this->assertNull($collection->next());
  14. $this->assertSame('bar', $collection->current());
  15. $this->assertSame(3, $collection->key());
  16. $collection->next();
  17. $this->assertFalse($collection->current());
  18. $this->assertNull($collection->key());
  19. $collection->rewind();
  20. $this->assertSame(0, $collection->key());
  21. $this->assertSame('hello', $collection->current());
  22. }

集合可统计

集合实现了 \Countable 可以像普通数组一样统计元素的个数。

  1. public function testCountable(): void
  2. {
  3. $data = [
  4. 'hello', 'world', 'foo', 'bar',
  5. ];
  6. $collection = new Collection($data);
  7. $this->assertCount(4, $collection);
  8. }

集合数据支持实现 \Leevel\Support\IArray 的对象

对象实现了 \Leevel\Support\IArray 可以转化为集合数据。

例子

  1. namespace Tests\Collection;
  2. class TestArray implements IArray
  3. {
  4. public function toArray(): array
  5. {
  6. return [
  7. 'hello',
  8. 'world',
  9. ];
  10. }
  11. }

实现了 \Leevel\Support\IArray 的对象的方法 toArray 返回集合的数据。

  1. public function testGetArrayElements2(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection(new TestArray());
  8. $this->assertSame($collection->toArray(), $data);
  9. }

集合数据支持实现 \Leevel\Support\IJson 的对象

对象实现了 \Leevel\Support\IJson 可以转化为集合数据。

例子

  1. namespace Tests\Collection;
  2. class TestJson implements IJson
  3. {
  4. public function toJson(?int $option = null): string
  5. {
  6. if (null === $option) {
  7. $option = JSON_UNESCAPED_UNICODE;
  8. }
  9. return json_encode([
  10. 'hello',
  11. 'world',
  12. ], $option);
  13. }
  14. }

实现了 \Leevel\Support\IJson 的对象的方法 toJson 返回集合的数据。

  1. public function testGetArrayElements3(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection(new TestJson());
  8. $this->assertSame($collection->toArray(), $data);
  9. }

集合数据支持实现 \JsonSerializable 的对象

对象实现了 \JsonSerializable 可以转化为集合数据。

例子

  1. namespace Tests\Collection;
  2. class TestJsonSerializable implements JsonSerializable
  3. {
  4. public function jsonSerialize()
  5. {
  6. return [
  7. 'hello',
  8. 'world',
  9. ];
  10. }
  11. }

实现了 \JsonSerializable 的对象的方法 jsonSerialize 返回集合的数据。

  1. public function testGetArrayElements4(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection(new TestJsonSerializable());
  8. $this->assertSame($collection->toArray(), $data);
  9. }

集合数据支持普通数据转化为数组

  1. public function testGetArrayElements5(): void
  2. {
  3. $data = [
  4. 'hello',
  5. ];
  6. $collection = new Collection('hello');
  7. $this->assertSame($collection->toArray(), $data);
  8. }

集合数据支持 \stdClass 的对象

对象为 \stdClass 可以转化为集合数据。

\stdClass 的对象返回转化为数组作为集合的数据。

  1. public function testGetArrayElementsWithStdClass(): void
  2. {
  3. $data = [
  4. 'hello' => 'world',
  5. 'foo' => 'bar',
  6. ];
  7. $std = new stdClass();
  8. $std->hello = 'world';
  9. $std->foo = 'bar';
  10. $collection = new Collection($std);
  11. $this->assertSame($collection->toArray(), $data);
  12. }

集合数据支持类型验证

比如下面的数据类型为 string,只有字符串类型才能加入集合。

  1. public function testTypeValidate(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection($data, ['string']);
  8. $this->assertSame($collection->toArray(), $data);
  9. $this->assertSame(['string'], $collection->getType());
  10. }

集合数据支持类型验证不符合规则示例

比如下面的数据类型为 int,字符串类型就会抛出异常。

  1. public function testTypeValidateException(): void
  2. {
  3. $this->expectException(\InvalidArgumentException::class);
  4. $this->expectExceptionMessage(
  5. 'Collection type int validation failed.'
  6. );
  7. $data = [
  8. 'hello',
  9. 'world',
  10. ];
  11. new Collection($data, ['int']);
  12. }

each 集合数据遍历元素项

使用闭包进行遍历,闭包的第一个参数为元素值,第二为元素键。

  1. public function testEach(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection($data);
  8. $i = 0;
  9. $collection->each(function ($item, $key) use (&$i) {
  10. $this->assertSame($i, $key);
  11. if (0 === $i) {
  12. $this->assertSame($item, 'hello');
  13. } else {
  14. $this->assertSame($item, 'world');
  15. }
  16. $i++;
  17. });
  18. }

each 集合数据遍历元素项支持中断

遍历元素项的时候返回 false 将会中断后续遍历操作。

  1. public function testEachAndBreak(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection($data);
  8. $i = 0;
  9. $collection->each(function ($item, $key) use (&$i) {
  10. $this->assertSame($i, $key);
  11. if (0 === $i) {
  12. $this->assertSame($item, 'hello');
  13. return false;
  14. }
  15. $i++;
  16. });
  17. $this->assertSame($i, 0);
  18. }

toJson 集合数据支持 JSON 输出

集合实现了 \Leevel\Support\IJson 接口,可以通过方法 toJson 输出 JSON 字符串。

  1. public function testToJson(): void
  2. {
  3. $data = [
  4. 'hello',
  5. 'world',
  6. ];
  7. $collection = new Collection($data);
  8. $data = '["hello","world"]';
  9. $this->assertSame($data, $collection->toJson());
  10. }

toJson 集合数据支持 JSON 输出默认不要编码 Unicode

JSON_UNESCAPED_UNICODE 可以让有中文的 JSON 字符串更加友好地输出。

  1. json_encode('中文', JSON_UNESCAPED_UNICODE);
  1. public function testToJsonWithCn(): void
  2. {
  3. $data = [
  4. '我',
  5. '成都',
  6. ];
  7. $collection = new Collection($data);
  8. $data = '["我","成都"]';
  9. $this->assertSame($data, $collection->toJson());
  10. }

toJson 集合数据支持 JSON 输出

集合实现了 \JsonSerializable 接口,可以通过方法 toJson 输出 JSON 字符串。

  1. public function testJsonSerialize(): void
  2. {
  3. $std = new stdClass();
  4. $std->hello = 'world';
  5. $std->foo = 'bar';
  6. $data = [
  7. new TestJsonSerializable(),
  8. new TestArray(),
  9. new TestJson(),
  10. $std,
  11. 'foo',
  12. 'bar',
  13. ];
  14. $collection = new Collection($data);
  15. $data = <<<'eot'
  16. [
  17. [
  18. "hello",
  19. "world"
  20. ],
  21. [
  22. "hello",
  23. "world"
  24. ],
  25. [
  26. "hello",
  27. "world"
  28. ],
  29. {
  30. "hello": "world",
  31. "foo": "bar"
  32. },
  33. "foo",
  34. "bar"
  35. ]
  36. eot;
  37. $this->assertSame(
  38. $data,
  39. $this->varJson(
  40. $collection->jsonSerialize()
  41. )
  42. );
  43. }

__toString 集合数据可以转化为字符串

集合实现了 __toString 方法,可以强制转化为字符串。

  1. public function testGetSetString(): void
  2. {
  3. $data = [
  4. 'hello' => 'world',
  5. 'foo' => 'bar',
  6. ];
  7. $collection = new Collection($data);
  8. $this->assertSame($collection->hello, 'world');
  9. $this->assertSame($collection->foo, 'bar');
  10. $collection->hello = 'new world';
  11. $collection->foo = 'new bar';
  12. $this->assertSame($collection->hello, 'new world');
  13. $this->assertSame($collection->foo, 'new bar');
  14. $this->assertSame((string) $collection, '{"hello":"new world","foo":"new bar"}');
  15. }