Passed
Push — master ( 12b94f...668c77 )
by Gilles
03:31
created

Content::copyUntil()   B

Complexity

Conditions 11
Paths 21

Size

Total Lines 56
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 11.0324

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 31
c 1
b 0
f 0
nc 21
nop 3
dl 0
loc 56
ccs 29
cts 31
cp 0.9355
crap 11.0324
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php 
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser;
6
7
8
use PHPHtmlParser\Exceptions\LogicalException;
9
10
/**
11
 * Class Content
12
 *
13
 * @package PHPHtmlParser
14
 */
15
class Content
16
{
17
18
    /**
19
     * The content string.
20
     *
21
     * @var string
22
     */
23
    protected $content;
24
25
    /**
26
     * The size of the content.
27
     *
28
     * @var integer
29
     */
30
    protected $size;
31
32
    /**
33
     * The current position we are in the content.
34
     *
35
     * @var integer
36
     */
37
    protected $pos;
38
39
    /**
40
     * The following 4 strings are tags that are important to us.
41
     *
42
     * @var string
43
     */
44
    protected $blank = " \t\r\n";
45
    protected $equal = ' =/>';
46
    protected $slash = " />\r\n\t";
47
    protected $attr = ' >';
48
49
    /**
50
     * Content constructor.
51
     *
52
     * @param string $content
53
     */
54 285
    public function __construct(string $content = '')
55
    {
56 285
        $this->content = $content;
57 285
        $this->size    = strlen($content);
58 285
        $this->pos     = 0;
59 285
    }
60
61
    /**
62
     * Returns the current position of the content.
63
     *
64
     * @return int
65
     */
66 6
    public function getPosition(): int
67
    {
68 6
        return $this->pos;
69
    }
70
71
    /**
72
     * Gets the current character we are at.
73
     *
74
     * @param ?int $char
75
     * @return string
76
     */
77 270
    public function char(?int $char = null): string
78
    {
79 270
        $pos = $this->pos;
80 270
        if ( ! is_null($char)) {
81 213
            $pos = $char;
82
        }
83
84 270
        if ( ! isset($this->content[$pos])) {
85 240
            return '';
86
        }
87
88 264
        return $this->content[$pos];
89
    }
90
91
    /**
92
     * Moves the current position forward.
93
     *
94
     * @param int $count
95
     * @return Content
96
     * @chainable
97
     */
98 255
    public function fastForward(int $count): Content
99
    {
100 255
        $this->pos += $count;
101
102 255
        return $this;
103
    }
104
105
    /**
106
     * Moves the current position backward.
107
     *
108
     * @param int $count
109
     * @return Content
110
     * @chainable
111
     */
112 18
    public function rewind(int $count): Content
113
    {
114 18
        $this->pos -= $count;
115 18
        if ($this->pos < 0) {
116 3
            $this->pos = 0;
117
        }
118
119 18
        return $this;
120
    }
121
122
    /**
123
     * Copy the content until we find the given string.
124
     *
125
     * @param string $string
126
     * @param bool $char
127
     * @param bool $escape
128
     * @return string
129
     */
130 261
    public function copyUntil(string $string, bool $char = false, bool $escape = false): string
131
    {
132 261
        if ($this->pos >= $this->size) {
133
            // nothing left
134 240
            return '';
135
        }
136
137 261
        if ($escape) {
138 231
            $position = $this->pos;
139 231
            $found    = false;
140 231
            while ( ! $found) {
141 231
                $position = strpos($this->content, $string, $position);
142 231
                if ($position === false) {
143
                    // reached the end
144 210
                    break;
145
                }
146
147 210
                if ($this->char($position - 1) == '\\') {
148
                    // this character is escaped
149 3
                    ++$position;
150 3
                    continue;
151
                }
152
153 210
                $found = true;
154
            }
155 258
        } elseif ($char) {
156 246
            $position = strcspn($this->content, $string, $this->pos);
157 246
            $position += $this->pos;
158
        } else {
159 252
            $position = strpos($this->content, $string, $this->pos);
160
        }
161
162 261
        if ($position === false) {
0 ignored issues
show
introduced by
The condition $position === false is always false.
Loading history...
163
            // could not find character, just return the remaining of the content
164 219
            $return    = substr($this->content, $this->pos, $this->size - $this->pos);
165 219
            if ($return === false) {
166
                throw new LogicalException('Substr returned false with position '.$this->pos.'.');
167
            }
168 219
            $this->pos = $this->size;
169
170 219
            return $return;
171
        }
172
173 252
        if ($position == $this->pos) {
174
            // we are at the right place
175 240
            return '';
176
        }
177
178 252
        $return = substr($this->content, $this->pos, $position - $this->pos);
179 252
        if ($return === false) {
180
            throw new LogicalException('Substr returned false with position '.$this->pos.'.');
181
        }
182
        // set the new position
183 252
        $this->pos = $position;
184
185 252
        return $return;
186
    }
187
188
    /**
189
     * Copies the content until the string is found and return it
190
     * unless the 'unless' is found in the substring.
191
     *
192
     * @param string $string
193
     * @param string $unless
194
     * @return string
195
     */
196 228
    public function copyUntilUnless(string $string, string $unless)
197
    {
198 228
        $lastPos = $this->pos;
199 228
        $this->fastForward(1);
200 228
        $foundString = $this->copyUntil($string, true, true);
201
202 228
        $position = strcspn($foundString, $unless);
203 228
        if ($position == strlen($foundString)) {
204 42
            return $string.$foundString;
205
        }
206
        // rewind changes and return nothing
207 228
        $this->pos = $lastPos;
208
209 228
        return '';
210
    }
211
212
    /**
213
     * Copies the content until it reaches the token string.,
214
     *
215
     * @param string $token
216
     * @param bool $char
217
     * @param bool $escape
218
     * @return string
219
     * @uses $this->copyUntil()
220
     */
221 243
    public function copyByToken(string $token, bool $char = false, bool $escape = false)
222
    {
223 243
        $string = $this->$token;
224
225 243
        return $this->copyUntil($string, $char, $escape);
226
    }
227
228
    /**
229
     * Skip a given set of characters.
230
     *
231
     * @param string $string
232
     * @param bool $copy
233
     * @return Content|string
234
     */
235 249
    public function skip(string $string, bool $copy = false)
236
    {
237 249
        $len = strspn($this->content, $string, $this->pos);
238
239
        // make it chainable if they don't want a copy
240 249
        $return = $this;
241 249
        if ($copy) {
242 234
            $return = substr($this->content, $this->pos, $len);
243 234
            if ($return === false) {
244
                throw new LogicalException('Substr returned false with position '.$this->pos.'.');
245
            }
246
        }
247
248
        // update the position
249 249
        $this->pos += $len;
250
251 249
        return $return;
252
    }
253
254
    /**
255
     * Skip a given token of pre-defined characters.
256
     *
257
     * @param string $token
258
     * @param bool $copy
259
     * @return Content|string
260
     * @uses $this->skip()
261
     */
262 243
    public function skipByToken(string $token, bool $copy = false)
263
    {
264 243
        $string = $this->$token;
265
266 243
        return $this->skip($string, $copy);
267
    }
268
}
269