PumpStream::read()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2
Metric Value
dl 0
loc 15
ccs 10
cts 10
cp 1
rs 9.4285
cc 2
eloc 10
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Thruster\Component\HttpMessage;
4
5
use Psr\Http\Message\StreamInterface;
6
7
/**
8
 * Class PumpStream
9
 *
10
 * @package Thruster\Component\HttpMessage
11
 * @author  Aurimas Niekis <[email protected]>
12
 */
13
class PumpStream implements StreamInterface
14
{
15
    /**
16
     * @var callable
17
     */
18
    private $source;
19
20
    /**
21
     * @var int
22
     */
23
    private $size;
24
25
    /**
26
     * @var int
27
     */
28
    private $tellPos;
29
30
    /**
31
     * @var array
32
     */
33
    private $metadata;
34
35
    /**
36
     * @var BufferStream
37
     */
38
    private $buffer;
39
40
    /**
41
     * @param callable $source Source of the stream data. The callable MAY
42
     *                         accept an integer argument used to control the
43
     *                         amount of data to return. The callable MUST
44
     *                         return a string when called, or false on error
45
     *                         or EOF.
46
     * @param array $options   Stream options:
47
     *                         - metadata: Hash of metadata to use with stream.
48
     *                         - size: Size of the stream, if known.
49
     */
50 5
    public function __construct(callable $source, array $options = [])
51
    {
52 5
        $this->tellPos = 0;
53 5
        $this->source = $source;
54 5
        $this->size = $options['size'] ?? null;
55 5
        $this->metadata = $options['metadata'] ?? [];
56 5
        $this->buffer = new BufferStream();
57 5
    }
58
59 1
    public function __toString()
60
    {
61
        try {
62 1
            return copy_to_string($this);
63
        } catch (\Exception $e) {
64
            return '';
65
        }
66
    }
67
68 1
    public function close()
69
    {
70 1
        $this->detach();
71 1
    }
72
73 1
    public function detach()
74
    {
75 1
        $this->tellPos = false;
0 ignored issues
show
Documentation Bug introduced by
The property $tellPos was declared of type integer, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
76 1
        $this->source = null;
77 1
    }
78
79 2
    public function getSize()
80
    {
81 2
        return $this->size;
82
    }
83
84 2
    public function tell()
85
    {
86 2
        return $this->tellPos;
87
    }
88
89 2
    public function eof() : bool
90
    {
91 2
        return !$this->source;
92
    }
93
94 2
    public function isSeekable() : bool
95
    {
96 2
        return false;
97
    }
98
99
    public function rewind()
100
    {
101
        $this->seek(0);
102
    }
103
104
    public function seek($offset, $whence = SEEK_SET)
105
    {
106
        throw new \RuntimeException('Cannot seek a PumpStream');
107
    }
108
109 1
    public function isWritable() : bool
110
    {
111 1
        return false;
112
    }
113
114 1
    public function write($string)
115
    {
116 1
        throw new \RuntimeException('Cannot write to a PumpStream');
117
    }
118
119 1
    public function isReadable() : bool
120
    {
121 1
        return true;
122
    }
123
124 4
    public function read($length)
125
    {
126 4
        $data = $this->buffer->read($length);
127 4
        $readLen = strlen($data);
128 4
        $this->tellPos += $readLen;
129 4
        $remaining = $length - $readLen;
130
131 4
        if ($remaining) {
132 4
            $this->pump($remaining);
133 4
            $data .= $this->buffer->read($remaining);
134 4
            $this->tellPos += strlen($data) - $readLen;
135
        }
136
137 4
        return $data;
138
    }
139
140 1
    public function getContents()
141
    {
142 1
        $result = '';
143 1
        while (!$this->eof()) {
144 1
            $result .= $this->read(1000000);
145
        }
146
147 1
        return $result;
148
    }
149
150 1
    public function getMetadata($key = null)
151
    {
152 1
        if (!$key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
153 1
            return $this->metadata;
154
        }
155
156 1
        return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
157
    }
158
159 4
    private function pump($length)
160
    {
161 4
        if ($this->source) {
162
            do {
163 4
                $data = call_user_func($this->source, $length);
164 4
                if ($data === false || $data === null) {
165 1
                    $this->source = null;
166 1
                    return;
167
                }
168 3
                $this->buffer->write($data);
169 3
                $length -= strlen($data);
170 3
            } while ($length > 0);
171
        }
172 4
    }
173
}
174