Skip to content

Commit 2e2825e

Browse files
committed
Add MsgPack serializer support
1 parent 7d5d0bf commit 2e2825e

4 files changed

Lines changed: 50 additions & 53 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ There are pretty much no dependencies with some exceptions:
2626

2727
- If you want to use the `toJSONFile()` method, you need to install `ext-json` (PHP's PECL JSON extension) as well.
2828
- If you want to use the igbinary serializer, `ext-igbinary` is required. See [php-ext-igbinary](https://github.com/igbinary/igbinary).
29+
- If you want to use the msgpack serializer, `ext-msgpack` is required. See [php-ext-msgpack](https://github.com/msgpack/msgpack-php).
2930
- If you want to use LZ4 compression, `ext-lz4` is required. See [php-ext-lz4](https://github.com/kjdev/php-ext-lz4).
3031

3132
## Usage
@@ -55,9 +56,9 @@ The constructor of `LargeArrayBuffer` provides some options:
5556

5657
1. You can set the threshold when to move the data to disk. When pushing data to the buffer, it is stored in memory until it gets too large.
5758
E.g.: `new LargeArrayBuffer(512);` to set a 512 MiB threshold.
58-
1. You can choose either the PHP serializer or the [igbinary](https://github.com/igbinary/igbinary) serializer (PHP serializer is default).
59+
1. You can choose either the PHP serializer, the [igbinary](https://github.com/igbinary/igbinary) serializer or the [msgpack](https://github.com/msgpack/msgpack-php) serializer (PHP serializer is default).
5960
E.g.: `new LargeArrayBuffer(serializer: LargeArrayBuffer::COMPRESSION_IGBINARY);`
60-
1. You can enable GZIP or LZ4 compression for the serialized items. Although this is recommended only if your items are pretty big like > 1 KiB each. E.g.: `new LargeArrayBuffer(compression: LargeArrayBuffer::COMPRESSION_GZIP);`. Note, that LZ4 compression requires [ext-lz4](https://github.com/kjdev/php-ext-lz4) to be installed.
61+
1. You can enable GZIP or LZ4 compression for the serialized items. Although this is recommended only if your items are pretty big like > 1 KiB each. E.g.: `new LargeArrayBuffer(compression: LargeArrayBuffer::COMPRESSION_GZIP);`. Note, that LZ4 compression requires [ext-lz4](https://github.com/kjdev/php-ext-lz4) to be loaded.
6162

6263
### Read from the buffer
6364

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"suggest": {
1515
"ext-json": "Requirement of toJSONFile() method",
1616
"ext-lz4": "To enable support of LZ4 compression",
17-
"ext-igbinary": "To enable support for igbinary serializer"
17+
"ext-igbinary": "To enable support for igbinary serializer",
18+
"ext-msgpack": "To enable support for msgpack serializer"
1819
},
1920
"require": {
2021
"php": ">=8.0"

src/LargeArrayBuffer.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class LargeArrayBuffer implements ArrayBufferInterface {
1212

1313
public const SERIALIZER_PHP = 1;
1414
public const SERIALIZER_IGBINARY = 2;
15+
public const SERIALIZER_MSGPACK = 3;
1516

1617
public const COMPRESSION_NONE = 0;
1718
public const COMPRESSION_GZIP = 1;
@@ -57,13 +58,16 @@ class LargeArrayBuffer implements ArrayBufferInterface {
5758
*/
5859
public function __construct(int $maxMemoryMiB = 1024, int $serializer = self::SERIALIZER_PHP, int $compression = self::COMPRESSION_NONE) {
5960
$this->serializer = $serializer;
60-
if($this->serializer === self::SERIALIZER_IGBINARY && !function_exists('igbinary_serialize')){
61-
throw new \InvalidArgumentException('igbinary serializer was requested, but ext-igbinary is not installed');
61+
if($this->serializer === self::SERIALIZER_IGBINARY && !extension_loaded('igbinary')){
62+
throw new \InvalidArgumentException('igbinary serializer was requested, but ext-igbinary is not loaded');
63+
}
64+
if($this->serializer === self::SERIALIZER_MSGPACK && !extension_loaded('msgpack')){
65+
throw new \InvalidArgumentException('msgpack serializer was requested, but ext-msgpack is not loaded');
6266
}
6367

6468
$this->compression = $compression;
65-
if($this->compression === self::COMPRESSION_LZ4 && !function_exists('lz4_compress')){
66-
throw new \InvalidArgumentException('LZ4 compression was requested, but ext-lz4 is not installed');
69+
if($this->compression === self::COMPRESSION_LZ4 && !extension_loaded('lz4')){
70+
throw new \InvalidArgumentException('LZ4 compression was requested, but ext-lz4 is not loaded');
6771
}
6872

6973
$stream = fopen('php://temp/maxmemory:'.($maxMemoryMiB * 1024 * 1024), 'r+');
@@ -80,6 +84,7 @@ public function __construct(int $maxMemoryMiB = 1024, int $serializer = self::SE
8084
public function push(mixed $item): void {
8185
$serialized = match($this->serializer){
8286
self::SERIALIZER_IGBINARY => igbinary_serialize($item),
87+
self::SERIALIZER_MSGPACK => msgpack_serialize($item),
8388
default => serialize($item)
8489
};
8590
/** @var string|false $compressed */
@@ -145,6 +150,7 @@ public function current(): mixed {
145150
/** @psalm-var E $res */
146151
$res = match($this->serializer){
147152
self::SERIALIZER_IGBINARY => igbinary_unserialize($this->current),
153+
self::SERIALIZER_MSGPACK => msgpack_unserialize($this->current),
148154
default => unserialize($this->current)
149155
};
150156
return $res;

test/LargeArrayBufferTest.php

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use LargeArrayBuffer\LargeArrayBuffer;
77
use PHPUnit\Framework\TestCase;
8+
use PHPUnit\Framework\Attributes\DataProvider;
89

910
/**
1011
* @author Andreas Wahlen
@@ -31,52 +32,44 @@ public function testEmpty(): void {
3132
$this->assertEquals(0, $runs);
3233
}
3334

34-
public static function provideObject(): array {
35-
$o = self::getObject();
36-
return [
37-
[$o, LargeArrayBuffer::SERIALIZER_PHP, LargeArrayBuffer::COMPRESSION_NONE],
38-
[$o, LargeArrayBuffer::SERIALIZER_PHP, LargeArrayBuffer::COMPRESSION_GZIP],
35+
public static function provideConfig(): \Generator {
36+
$serializers = [
37+
'PHP' => LargeArrayBuffer::SERIALIZER_PHP
3938
];
39+
if(extension_loaded('igbinary')){
40+
$serializers['IGBinary'] = LargeArrayBuffer::SERIALIZER_IGBINARY;
41+
}
42+
if(extension_loaded('msgpack')){
43+
$serializers['MsgPack'] = LargeArrayBuffer::SERIALIZER_MSGPACK;
44+
}
45+
$compressors = [
46+
'none' => LargeArrayBuffer::COMPRESSION_NONE,
47+
'GZIP' => LargeArrayBuffer::COMPRESSION_GZIP
48+
];
49+
if(extension_loaded('lz4')){
50+
$compressors['LZ4'] = LargeArrayBuffer::COMPRESSION_LZ4;
51+
}
52+
foreach($serializers as $s => $serializer){
53+
foreach($compressors as $c => $compressor){
54+
yield $s.'-'.$c => [$serializer, $compressor];
55+
}
56+
}
4057
}
4158

42-
/**
43-
* @dataProvider provideObject
44-
*/
45-
public function testReadWrite(object $o, int $serializer, int $compression): void {
46-
$buf = new LargeArrayBuffer(serializer: $serializer, compression: $compression);
47-
$buf->push($o);
48-
$buf->rewind();
49-
$buf->next();
50-
$this->assertEquals($o, $buf->current());
51-
}
52-
53-
/**
54-
* @requires extension igbinary
55-
*/
56-
public function testReadWriteIgbinary(): void {
57-
$o = self::getObject();
58-
$buf = new LargeArrayBuffer(serializer: LargeArrayBuffer::SERIALIZER_IGBINARY);
59-
$buf->push($o);
60-
$buf->rewind();
61-
$buf->next();
62-
$this->assertEquals($o, $buf->current());
63-
}
64-
65-
/**
66-
* @requires extension lz4
67-
*/
68-
public function testReadWriteLZ4(): void {
59+
#[DataProvider('provideConfig')]
60+
public function testReadWrite(int $serializer, int $compression): void {
6961
$o = self::getObject();
70-
$buf = new LargeArrayBuffer(compression: LargeArrayBuffer::COMPRESSION_LZ4);
62+
$buf = new LargeArrayBuffer(serializer: $serializer, compression: $compression);
7163
$buf->push($o);
7264
$buf->rewind();
7365
$buf->next();
7466
$this->assertEquals($o, $buf->current());
7567
}
7668

77-
public function testLoop(): void {
78-
$count = 15;
79-
$buf = new LargeArrayBuffer();
69+
#[DataProvider('provideConfig')]
70+
public function testLoop(int $serializer, int $compression): void {
71+
$count = 1500;
72+
$buf = new LargeArrayBuffer(serializer: $serializer, compression: $compression);
8073
$objs = [];
8174
for($i=0;$i<$count;$i++){
8275
$o = new \stdClass();
@@ -85,22 +78,18 @@ public function testLoop(): void {
8578
$buf->push($o);
8679
}
8780
$this->assertCount($count, $buf);
88-
$runs = 0;
81+
$expIdx = 0;
8982
foreach($buf as $idx => $item){
90-
$runs++;
91-
$this->assertGreaterThanOrEqual(0, $idx);
92-
$this->assertLessThan($count, $idx);
83+
$this->assertEquals($expIdx, $idx);
84+
$this->assertEquals($item->idx, $idx);
9385
$this->assertEquals($objs[$idx], $item);
86+
$expIdx++;
9487
}
95-
$this->assertEquals($count, $runs);
88+
$this->assertEquals($count, $expIdx);
9689
}
9790

9891
public function testToJSON(): void {
99-
$o = new \stdClass();
100-
$o->foo = 'hello world!'.PHP_EOL;
101-
$o->bar = new \DateTimeImmutable();
102-
$o->a = ['test', 123];
103-
$o->str = 'hello world!\\n';
92+
$o = self::getObject();
10493

10594
$buf = new LargeArrayBuffer();
10695
$buf->push($o);

0 commit comments

Comments
 (0)