Skip to content

Commit fc2816f

Browse files
committed
Change Compressor to use more efficient deflate_init() context
1 parent 8918853 commit fc2816f

File tree

3 files changed

+44
-20
lines changed

3 files changed

+44
-20
lines changed

src/Compressor.php

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,43 @@
3131
* For more details, see ReactPHP's
3232
* [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
3333
*/
34-
final class Compressor extends ZlibFilterStream
34+
final class Compressor extends TransformStream
3535
{
36+
/** @var ?resource */
37+
private $context;
38+
3639
/**
3740
* @param int $encoding ZLIB_ENCODING_GZIP, ZLIB_ENCODING_RAW or ZLIB_ENCODING_DEFLATE
3841
* @param int $level optional compression level
3942
*/
4043
public function __construct($encoding, $level = -1)
4144
{
42-
parent::__construct(
43-
Filter\fun('zlib.deflate', array('window' => $encoding, 'level' => $level))
44-
);
45+
$context = @deflate_init($encoding, ['level' => $level]);
46+
if ($context === false) {
47+
throw new \InvalidArgumentException('Unable to initialize compressor' . strstr(error_get_last()['message'], ':'));
48+
}
49+
50+
$this->context = $context;
51+
}
52+
53+
protected function transformData($chunk)
54+
{
55+
$ret = deflate_add($this->context, $chunk, ZLIB_NO_FLUSH);
56+
57+
if ($ret !== '') {
58+
$this->forwardData($ret);
59+
}
60+
}
61+
62+
protected function transformEnd($chunk)
63+
{
64+
$ret = deflate_add($this->context, $chunk, ZLIB_FINISH);
65+
$this->context = null;
66+
67+
if ($ret !== '') {
68+
$this->forwardData($ret);
69+
}
4570

46-
$this->emptyWrite = $encoding;
71+
$this->forwardEnd();
4772
}
4873
}

src/ZlibFilterStream.php

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ class ZlibFilterStream extends TransformStream
2020
{
2121
private $filter;
2222

23-
/**
24-
* @var int|null
25-
* @see Compressor
26-
* @internal
27-
*/
28-
protected $emptyWrite;
29-
3023
public function __construct($filter)
3124
{
3225
$this->filter = $filter;
@@ -38,7 +31,6 @@ protected function transformData($chunk)
3831
$ret = $filter($chunk);
3932

4033
if ($ret !== '') {
41-
$this->emptyWrite = null;
4234
$this->forwardData($ret);
4335
}
4436
}
@@ -48,13 +40,6 @@ protected function transformEnd($chunk)
4840
$filter = $this->filter;
4941
$ret = $filter($chunk) . $filter();
5042

51-
// Stream ends successfully and did not emit any data whatsoever?
52-
// This happens when compressing an empty stream with PHP 7 only.
53-
// Bypass filter and manually compress/encode empty string.
54-
if ($this->emptyWrite !== null && $ret === '') {
55-
$ret = \zlib_encode('', $this->emptyWrite);
56-
}
57-
5843
if ($ret !== '') {
5944
$this->forwardData($ret);
6045
}

tests/CompressorTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
use Clue\React\Zlib\Compressor;
4+
5+
class CompressorTest extends TestCase
6+
{
7+
/**
8+
* @expectedException InvalidArgumentException
9+
*/
10+
public function testCtorThrowsForInvalidEncoding()
11+
{
12+
new Compressor(0);
13+
}
14+
}

0 commit comments

Comments
 (0)