DefaultStream   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 217
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 96.83%

Importance

Changes 11
Bugs 3 Features 3
Metric Value
wmc 18
c 11
b 3
f 3
lcom 1
cbo 4
dl 0
loc 217
ccs 61
cts 63
cp 0.9683
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A connect() 0 17 2
A close() 0 9 1
A readLine() 0 15 2
A readBytes() 0 14 2
A write() 0 15 3
A isConnected() 0 4 1
A getNodeUrl() 0 4 1
A streamWrite() 0 4 1
A streamReadBytes() 0 4 1
A streamReadLine() 0 4 1
A streamMeta() 0 4 1
1
<?php
2
3
namespace Phloppy\Stream;
4
5
use Phloppy\Exception\ConnectException;
6
use Psr\Log\LoggerInterface;
7
use Psr\Log\NullLogger;
8
9
class DefaultStream implements StreamInterface
10
{
11
12
    /**
13
     * The remote socket url.
14
     *
15
     * @var string
16
     */
17
    private $nodeUrl;
18
19
    /**
20
     * @var LoggerInterface
21
     */
22
    private $log;
23
24
    /**
25
     * @var resource
26
     */
27
    private $stream;
28
29
30 33
    public function __construct($nodeUrl, LoggerInterface $log = null)
31
    {
32 33
        if (!$log) {
33 5
            $log = new NullLogger();
34 5
        }
35
36 33
        $this->log = $log;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
37 33
        $this->nodeUrl = $nodeUrl;
38 33
    }
39
40
41
    /**
42
     * Connect the stream.
43
     *
44
     * @return boolean True if connection could be established.
45
     *
46
     * @throws ConnectException
47
     */
48 30
    public function connect()
49
    {
50 30
        $connectTimeout = 1;
51 30
        $errstr = '';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
52 30
        $errno = 0;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
53 30
        $stream = @stream_socket_client($this->nodeUrl, $errno, $errstr, $connectTimeout);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
54
55 30
        if (!$stream) {
56 2
            $this->log->warning('unable to connect to '.$this->nodeUrl.': '.$errstr);
57 2
            throw new ConnectException('Unable to connect to resource '.$this->nodeUrl.'. '.$errstr, $errno);
58
        }
59
60 28
        $this->log->info('connected to '.$this->nodeUrl);
61 28
        $this->stream = $stream;
62
63 28
        return true;
64
    }
65
66
67 27
    public function close()
68
    {
69 27
        $this->log->info('closing connection: '.$this->nodeUrl);
70 27
        stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR);
71 27
        $this->stream = null;
72 27
        $this->log->info('connection closed: '.$this->nodeUrl);
73
74 27
        return true;
75
    }
76
77
78
    /**
79
     * Read a line from the stream.
80
     *
81
     * @return string
82
     * @throws StreamException If an error occurs while reading from the stream.
83
     */
84 24
    public function readLine()
85
    {
86 24
        $this->log->debug('going to read a line from the stream');
87 24
        $line = $this->streamReadLine($this->stream);
88
89 24
        if (false === $line) {
90 1
            $meta = $this->streamMeta($this->stream);
91 1
            $this->log->warning('fgets returned false', $meta);
92 1
            throw new StreamException(StreamException::OP_READ, 'stream_get_line returned false');
93
        }
94
95 23
        $this->log->debug('readLine()', [$line]);
96
97 23
        return $line;
98
    }
99
100
101
    /**
102
     * Read bytes off from the stream.
103
     *
104
     * @param int|null $maxlen
105
     *
106
     * @return string
107
     * @throws StreamException If an error occurs while reading from the stream.
108
     */
109 14
    public function readBytes($maxlen = null)
110
    {
111 14
        $this->log->debug('calling readbytes()', array('maxlen' => $maxlen));
112 14
        $out = $this->streamReadBytes($this->stream, $maxlen);
113 14
        $this->log->debug('readBytes()', [$maxlen, $out]);
114
115 14
        if (false === $out) {
116 1
            $meta = $this->streamMeta($this->stream);
117 1
            $this->log->warning('stream_get_contents returned false', $meta);
118 1
            throw new StreamException(StreamException::OP_READ, 'stream_get_contents returned false');
119
        }
120
121 13
        return $out;
122
    }
123
124
125
    /**
126
     * Write bytes to the stream.
127
     *
128
     * @param string   $msg
129
     * @param int|null $len
130
     *
131
     * @return DefaultStream this instance.
132
     * @throws StreamException
133
     */
134 24
    public function write($msg, $len = null)
135
    {
136 24
        if (!$len) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $len of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
137 24
            $len = strlen($msg);
138 24
        }
139
140 24
        $bytes = $this->streamWrite($this->stream, $msg);
141 24
        $this->log->debug('write()', ['written' => $bytes, 'len' => $len, 'msg' => $msg]);
142
143 24
        if ($bytes !== $len) {
144 1
            throw new StreamException(StreamException::OP_WRITE, 'unable to write to stream');
145
        }
146
147 23
        return $this;
148
    }
149
150
151
    /**
152
     * Check if the stream is connected.
153
     *
154
     * @return boolean True if the stream is connected.
155
     */
156 3
    public function isConnected()
157
    {
158 3
        return is_resource($this->stream);
159
    }
160
161
162
    /**
163
     * return the internal node url.
164
     *
165
     * @return string
166
     */
167 2
    public function getNodeUrl()
168
    {
169 2
        return $this->nodeUrl;
170
    }
171
172
173
    /**
174
     * Internal wrapper method, mainly for testing.
175
     *
176
     * @param resource $stream
177
     * @param string   $msg
178
     *
179
     * @return int
180
     */
181 23
    protected function streamWrite($stream, $msg)
182
    {
183 23
        return fwrite($stream, $msg);
184
    }
185
186
187
    /**
188
     * Internal wrapper method, mainly for testing.
189
     *
190
     * @param resource $stream
191
     * @param          $len
192
     *
193
     * @return string
194
     */
195 13
    protected function streamReadBytes($stream, $len)
196
    {
197 13
        return stream_get_contents($stream, $len);
198
    }
199
200
201
    /**
202
     * Internal wrapper method, mainly for testing.
203
     *
204
     * @param resource $stream
205
     *
206
     * @return string
207
     */
208 23
    protected function streamReadLine($stream)
209
    {
210 23
        return fgets($stream, 8192);
211
    }
212
213
214
    /**
215
     * Internal wrapper method, mainly for testing.
216
     *
217
     * @param $stream
218
     *
219
     * @return array
220
     */
221
    protected function streamMeta($stream)
222
    {
223
        return stream_get_meta_data($stream);
224
    }
225
}
226