StreamSource::read()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.8437

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 13
ccs 5
cts 8
cp 0.625
crap 4.8437
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace JsonDecodeStream\Source;
5
6
use JsonDecodeStream\Exception\SourceException;
7
8
class StreamSource implements SourceInterface
9
{
10
    /** @var resource */
11
    protected $stream;
12
13
    /**
14
     * StreamSource constructor.
15
     * @param $stream
16
     * @throws SourceException
17
     */
18 60
    public function __construct($stream)
19
    {
20 60
        if (!is_resource($stream)) {
21 1
            throw new SourceException('Argument is not a resource');
22
        }
23 59
        $this->stream = $stream;
24 59
    }
25
26 58
    public function isEof(): bool
27
    {
28 58
        return feof($this->stream);
29
    }
30
31 62
    public function read(int $bytes): string
32
    {
33
        try {
34 62
            $read = fread($this->stream, $bytes);
35 62
            if ($read === false) {
36
                $error = error_get_last();
37 62
                throw new \RuntimeException($error ? $error['message'] : 'fread error');
38
            }
39
        } catch (\Throwable $e) {
40
            throw new SourceException('Cound not read from stream', 0, $e);
41
        }
42
43 62
        return $read;
44
    }
45
46 57
    public function rewind(): void
47
    {
48
        try {
49 57
            $tell = ftell($this->stream);
50 57
            if ($tell === false) {
51
                $error = error_get_last();
52
                throw new \RuntimeException($error ? $error['message'] : 'ftell error');
53
            }
54 57
            if ($tell === 0) {
55 55
                return;
56
            }
57
58 3
            $streamMetaData = stream_get_meta_data($this->stream);
59 3
            if (!$streamMetaData['seekable']) {
60 1
                throw new SourceException('This stream is not seekable, can not rewind after data was read');
61
            }
62
63 2
            $seek = fseek($this->stream, 0, SEEK_SET);
64 2
            if ($seek === -1) {
65
                $error = error_get_last();
66 2
                throw new \RuntimeException($error ? $error['message'] : 'fseek error');
67
            }
68 1
        } catch (\Throwable $e) {
69 1
            throw new SourceException('Cound not seek the stream', 0, $e);
70
        }
71 2
    }
72
}
73