Completed
Push — master ( 938fdb...bc474a )
by Alex
01:39
created

Buffer::canWrite()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 0
crap 3
1
<?php
2
declare(strict_types=1);
3
4
namespace FakeSocket\Stream;
5
6
use FakeSocket\StreamWrapper;
7
8
final class Buffer implements StreamWrapper
9
{
10
    /** @var string */
11
    private $stream = '';
12
13
    /** @var int */
14
    private $position = 0;
15
16
    /** @var int */
17
    private $readCount = 0;
18
19
    /** @var int */
20
    private $writeCount = 0;
21
22
    /** @var array */
23
    private $limits = [
24
        'read'        => -1,
25
        'read_after'  => 0,
26
        'read_every'  => 1,
27
        'write'       => -1,
28
        'write_after' => 0,
29
        'write_every' => 1,
30
    ];
31
32 11
    public function stream_open($path, $mode, $options, &$opened_path)
0 ignored issues
show
Unused Code introduced by
The parameter $mode is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $opened_path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
Method name "Buffer::stream_open" is not in camel caps format
Loading history...
33
    {
34 11
        $components = parse_url($path);
35
36 11
        static $query = [];
37
38 11
        if (isset($components['query'])) {
39 4
            parse_str($components['query'], $query);
40
        }
41
42 11
        $this->configureLimits($query);
0 ignored issues
show
Bug introduced by
It seems like $query can also be of type null; however, FakeSocket\Stream\Buffer::configureLimits() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
43
44 11
        return true;
45
    }
46
47 7
    public function stream_eof()
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_eof" is not in camel caps format
Loading history...
48
    {
49 7
        return $this->position >= strlen($this->stream);
50
    }
51
52 3
    public function stream_tell()
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_tell" is not in camel caps format
Loading history...
53
    {
54 3
        return $this->position;
55
    }
56
57 8
    public function stream_write($data)
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_write" is not in camel caps format
Loading history...
58
    {
59 8
        ++$this->writeCount;
60
61 8
        if (!$this->canWrite()) {
62 2
            return false;
63
        }
64
65 8
        $left = substr($this->stream, 0, $this->position);
66
67 8
        $this->stream = "{$left}{$data}";
68 8
        $this->position += $bytesWritten = strlen($data);
69
70 8
        return $bytesWritten;
71
    }
72
73 3
    public function stream_read($count)
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_read" is not in camel caps format
Loading history...
74
    {
75 3
        ++$this->readCount;
76
77 3
        if (!$this->canRead()) {
78 1
            return false;
79
        }
80
81 3
        $data = substr($this->stream, $this->position, $count);
82
83 3
        if (false === $data) {
84 1
            return false;
85
        }
86
87 2
        $this->position += strlen($data);
88
89 2
        return $data;
90
    }
91
92 3
    public function stream_seek($offset, $whence)
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_seek" is not in camel caps format
Loading history...
93
    {
94 3
        static $values = [SEEK_SET, SEEK_CUR, SEEK_END];
95
96 3
        if (in_array($whence, $values)) {
97 3
            if (SEEK_END === $whence) {
98 1
                $offset = strlen($this->stream) + $offset;
99
            }
100
101 3
            if ($offset >= 0) {
102 3
                $this->position = $offset;
103 3
                return true;
104
            }
105
        }
106
107
        return false;
108
    }
109
110 2
    public function stream_stat()
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_stat" is not in camel caps format
Loading history...
111
    {
112 2
        return [];
113
    }
114
115 2
    public function stream_truncate($new_size)
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_truncate" is not in camel caps format
Loading history...
116
    {
117 2
        $currentLength = strlen($this->stream);
118
119 2
        if ($new_size > $currentLength) {
120 1
            $multiplier = $new_size - $currentLength;
121 1
            $this->stream .= str_repeat(chr(0), $multiplier);
122
123 1
            return true;
124
        }
125
126 1
        $this->stream = substr($this->stream, 0, $new_size);
127
128 1
        return true;
129
    }
130
131 1
    public function stream_set_option($option, $arg1, $arg2)
0 ignored issues
show
Coding Style introduced by
Method name "Buffer::stream_set_option" is not in camel caps format
Loading history...
132
    {
133 1
        return true;
134
    }
135
136 11
    private function configureLimits(array $query): void
137
    {
138 11
        foreach (array_keys($this->limits) as $limit) {
139 11
            if (!isset($query[$limit])) {
140 11
                continue;
141
            }
142
143 10
            if (false !== strrpos($limit, 'every')) {
144 2
                $query[$limit] = max(1, (int) $query[$limit]);
145
            }
146
147 10
            $this->limits[$limit] = (int) $query[$limit];
148
        }
149 11
    }
150
151 3
    private function canRead(): bool
152
    {
153 3
        $noLimit = $this->readCount !== $this->limits['read'] + 1;
154
155 3
        return $noLimit
156 3
            && $this->readCount > $this->limits['read_after']
157 3
            && $this->readCount % $this->limits['read_every'] === 0;
158
    }
159
160 8
    private function canWrite(): bool
161
    {
162 8
        $noLimit = $this->writeCount !== $this->limits['write'] + 1;
163
164 8
        return $noLimit
165 8
            && $this->writeCount > $this->limits['write_after']
166 8
            && $this->writeCount % $this->limits['write_every'] === 0;
167
    }
168
}
169