From 1674332ac779cd10779dee9fcace7d78daf2d9ee Mon Sep 17 00:00:00 2001 From: Andreas Wahlen Date: Mon, 10 Mar 2025 18:16:40 +0100 Subject: [PATCH 1/2] Add toFixedArray and toGenerator methods --- README.md | 7 ++++++ src/ArrayBuffer.php | 32 +++++++++++++++++++++++++ src/ArrayBufferInterface.php | 11 +++++++++ src/LargeArrayBuffer.php | 24 +++++++++++++++++++ test/LargeArrayBufferTest.php | 45 +++++++++++++++++++++++++++++++---- 5 files changed, 114 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cbc11c7..23129da 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ You can still iterate over it as if it was a normal array. One typical use case would be to load a lot of datasets from a database at once. (There are reasons to prefer this over running multiple queries.) See *Usage* below for an example for this use case using this library. +In general, you might want to try the following PHP-builtin solutions first: + +- [SplFixedArray](https://www.php.net/manual/class.splfixedarray.php): By being of fixed length, this saves some memory compared to traditional `array`s. It behaves pretty much like `array`s do. Although the savings are not that huge compared to other solutions, it is probably the easiest to adopt. +- [Generator](https://www.php.net/manual/language.generators.php): Instead of returning an `array` all at once, this allows to return one item after the other. Thereby a "consumer" is able to process one item after the other accordingly. One can also terminate the "generation" of further items. One of the downsides is, that a Generator can only be iterated over once. The memory consumption can be as good as constant, but this approach is quite different and therefore rather hard to adopt and not appropriate in every scenario. + +It should be noted, that a `LargeArrayBuffer` can be converted to both of these using `toFixedArray()` and `toGenerator()` respectively. + ## Install Note: This library requires PHP 8.0+! diff --git a/src/ArrayBuffer.php b/src/ArrayBuffer.php index 291d3e7..ddcc0dc 100644 --- a/src/ArrayBuffer.php +++ b/src/ArrayBuffer.php @@ -112,4 +112,36 @@ public function toArray(): array { return $this->array; } } + + /** + * @psalm-return \SplFixedArray + */ + public function toFixedArray(): \SplFixedArray { + if($this->buffer->count() > 0){ + return $this->buffer->toFixedArray(); + } else { + $res = new \SplFixedArray(count($this->array)); + foreach($this->array as $idx => $item){ + $res[$idx] = $item; + } + return $res; + } + } + + /** + * @return \Generator send something other than null to terminate + * @psalm-return \Generator + */ + public function toGenerator(): \Generator { + if($this->buffer->count() > 0){ + yield from $this->buffer->toGenerator(); + } else { + foreach($this->array as $item){ + $cmd = yield $item; + if($cmd !== null){ + break; + } + } + } + } } diff --git a/src/ArrayBufferInterface.php b/src/ArrayBufferInterface.php index 8086477..e3fb30f 100644 --- a/src/ArrayBufferInterface.php +++ b/src/ArrayBufferInterface.php @@ -20,4 +20,15 @@ public function push(mixed $item): void; * @psalm-return list */ public function toArray(): array; + + /** + * @psalm-return \SplFixedArray + */ + public function toFixedArray(): \SplFixedArray; + + /** + * @return \Generator send something other than null to terminate + * @psalm-return \Generator + */ + public function toGenerator(): \Generator; } diff --git a/src/LargeArrayBuffer.php b/src/LargeArrayBuffer.php index 471da2c..995de0d 100644 --- a/src/LargeArrayBuffer.php +++ b/src/LargeArrayBuffer.php @@ -236,6 +236,30 @@ public function toArray(): array { } return $res; } + + /** + * @psalm-return \SplFixedArray + */ + public function toFixedArray(): \SplFixedArray { + $res = new \SplFixedArray($this->count); + foreach($this as $idx => $item){ + $res[$idx] = $item; + } + return $res; + } + + /** + * @return \Generator send something other than null to terminate + * @psalm-return \Generator + */ + public function toGenerator(): \Generator { + foreach($this as $item){ + $cmd = yield $item; + if($cmd !== null){ + break; + } + } + } public function __destruct() { /** diff --git a/test/LargeArrayBufferTest.php b/test/LargeArrayBufferTest.php index f461641..4f01631 100644 --- a/test/LargeArrayBufferTest.php +++ b/test/LargeArrayBufferTest.php @@ -96,11 +96,7 @@ public function testLoop(): void { } public function testToJSON(): void { - $o = new \stdClass(); - $o->foo = 'hello world!'.PHP_EOL; - $o->bar = new \DateTimeImmutable(); - $o->a = ['test', 123]; - $o->str = 'hello world!\\n'; + $o = $this->getObject(); $buf = new LargeArrayBuffer(); $buf->push($o); @@ -112,4 +108,43 @@ public function testToJSON(): void { fclose($stream); $this->assertEquals(json_encode([$o, $o], JSON_THROW_ON_ERROR), $json); } + + public function provideItems(): array { + return [ + [['hello world!', 'just another string']] + ]; + } + + /** + * @dataProvider provideItems + */ + public function testToArray(array $items): void { + $buf = new LargeArrayBuffer(); + foreach($items as $item){ + $buf->push($item); + } + $this->assertSame($items, $buf->toArray()); + } + + /** + * @dataProvider provideItems + */ + public function testToFixedArray(array $items): void { + $buf = new LargeArrayBuffer(); + foreach($items as $item){ + $buf->push($item); + } + $this->assertSame($items, $buf->toFixedArray()->toArray()); + } + + /** + * @dataProvider provideItems + */ + public function testToGenerator(array $items): void { + $buf = new LargeArrayBuffer(); + foreach($items as $item){ + $buf->push($item); + } + $this->assertSame($items, iterator_to_array($buf->toGenerator())); + } } From a838d7e1f8d018244cd1e1ccfd4a03bbf2dfbf25 Mon Sep 17 00:00:00 2001 From: Andreas Wahlen Date: Mon, 10 Mar 2025 19:09:23 +0100 Subject: [PATCH 2/2] Remove unused `use` --- test/LargeArrayBufferTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/test/LargeArrayBufferTest.php b/test/LargeArrayBufferTest.php index 74de713..939ee9a 100644 --- a/test/LargeArrayBufferTest.php +++ b/test/LargeArrayBufferTest.php @@ -5,7 +5,6 @@ use LargeArrayBuffer\LargeArrayBuffer; use PHPUnit\Framework\TestCase; -use PHPUnit\Framework\Attributes\DataProvider; /** * @author Andreas Wahlen