Conditions | 84 |
Paths | 233 |
Total Lines | 260 |
Lines | 39 |
Ratio | 15 % |
Changes | 0 |
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:
If many parameters/temporary variables are present:
1 | <?php |
||
97 | public function parseString(PHPTAL_Dom_DocumentBuilder $builder, $src, $filename = '<string>') |
||
98 | { |
||
99 | try |
||
100 | { |
||
101 | $builder->setEncoding($this->input_encoding); |
||
102 | $this->_file = $filename; |
||
103 | |||
104 | $this->_line = 1; |
||
105 | $state = self::ST_ROOT; |
||
106 | $mark = 0; |
||
107 | $len = strlen($src); |
||
108 | |||
109 | $quoteStyle = '"'; |
||
110 | $tagname = ""; |
||
111 | $attribute = ""; |
||
112 | $attributes = array(); |
||
113 | |||
114 | $customDoctype = false; |
||
115 | |||
116 | $builder->setSource($this->_file, $this->_line); |
||
117 | $builder->onDocumentStart(); |
||
118 | |||
119 | $i=0; |
||
120 | // remove BOM (UTF-8 byte order mark)... |
||
121 | if (substr($src, 0, 3) === self::BOM_STR) { |
||
122 | $i=3; |
||
123 | } |
||
124 | for (; $i<$len; $i++) { |
||
125 | $c = $src[$i]; // Change to substr($src, $i, 1); if you want to use mb_string.func_overload |
||
126 | |||
127 | if ($c === "\n") $builder->setSource($this->_file, ++$this->_line); |
||
128 | |||
129 | switch ($state) { |
||
130 | View Code Duplication | case self::ST_ROOT: |
|
|
|||
131 | if ($c === '<') { |
||
132 | $mark = $i; // mark tag start |
||
133 | $state = self::ST_LT; |
||
134 | } elseif (!self::isWhiteChar($c)) { |
||
135 | $this->raiseError("Characters found before beginning of the document! (wrap document in < tal:block > to avoid this error)"); |
||
136 | } |
||
137 | break; |
||
138 | |||
139 | case self::ST_TEXT: |
||
140 | if ($c === '<') { |
||
141 | if ($mark != $i) { |
||
142 | $builder->onElementData($this->sanitizeEscapedText($this->checkEncoding(substr($src, $mark, $i-$mark)))); |
||
143 | } |
||
144 | $mark = $i; |
||
145 | $state = self::ST_LT; |
||
146 | } |
||
147 | break; |
||
148 | |||
149 | case self::ST_LT: |
||
150 | if ($c === '/') { |
||
151 | $mark = $i+1; |
||
152 | $state = self::ST_TAG_CLOSE; |
||
153 | View Code Duplication | } elseif ($c === '?' and strtolower(substr($src, $i, 5)) === '?xml ') { |
|
154 | $state = self::ST_XMLDEC; |
||
155 | } elseif ($c === '?') { |
||
156 | $state = self::ST_PREPROC; |
||
157 | View Code Duplication | } elseif ($c === '!' and substr($src, $i, 3) === '!--') { |
|
158 | $state = self::ST_COMMENT; |
||
159 | } elseif ($c === '!' and substr($src, $i, 8) === '![CDATA[') { |
||
160 | $state = self::ST_CDATA; |
||
161 | $mark = $i+8; // past opening tag |
||
162 | View Code Duplication | } elseif ($c === '!' and strtoupper(substr($src, $i, 8)) === '!DOCTYPE') { |
|
163 | $state = self::ST_DOCTYPE; |
||
164 | } elseif (self::isWhiteChar($c)) { |
||
165 | $state = self::ST_TEXT; |
||
166 | } else { |
||
167 | $mark = $i; // mark node name start |
||
168 | $attributes = array(); |
||
169 | $attribute = ""; |
||
170 | $state = self::ST_TAG_NAME; |
||
171 | } |
||
172 | break; |
||
173 | |||
174 | case self::ST_TAG_NAME: |
||
175 | if (self::isWhiteChar($c) || $c === '/' || $c === '>') { |
||
176 | $tagname = substr($src, $mark, $i-$mark); |
||
177 | if (!$this->isValidQName($tagname)) $this->raiseError("Invalid tag name '$tagname'"); |
||
178 | |||
179 | if ($c === '/') { |
||
180 | $state = self::ST_TAG_SINGLE; |
||
181 | } elseif ($c === '>') { |
||
182 | $mark = $i+1; // mark text start |
||
183 | $state = self::ST_TEXT; |
||
184 | $builder->onElementStart($tagname, $attributes); |
||
185 | } else /* isWhiteChar */ { |
||
186 | $state = self::ST_TAG_ATTRIBUTES; |
||
187 | } |
||
188 | } |
||
189 | break; |
||
190 | |||
191 | case self::ST_TAG_CLOSE: |
||
192 | if ($c === '>') { |
||
193 | $tagname = rtrim(substr($src, $mark, $i-$mark)); |
||
194 | $builder->onElementClose($tagname); |
||
195 | $mark = $i+1; // mark text start |
||
196 | $state = self::ST_TEXT; |
||
197 | } |
||
198 | break; |
||
199 | |||
200 | case self::ST_TAG_SINGLE: |
||
201 | if ($c !== '>') { |
||
202 | $this->raiseError("Expected '/>', but found '/$c' inside tag < $tagname >"); |
||
203 | } |
||
204 | $mark = $i+1; // mark text start |
||
205 | $state = self::ST_TEXT; |
||
206 | $builder->onElementStart($tagname, $attributes); |
||
207 | $builder->onElementClose($tagname); |
||
208 | break; |
||
209 | |||
210 | case self::ST_TAG_BETWEEN_ATTRIBUTE: |
||
211 | case self::ST_TAG_ATTRIBUTES: |
||
212 | if ($c === '>') { |
||
213 | $mark = $i+1; // mark text start |
||
214 | $state = self::ST_TEXT; |
||
215 | $builder->onElementStart($tagname, $attributes); |
||
216 | } elseif ($c === '/') { |
||
217 | $state = self::ST_TAG_SINGLE; |
||
218 | } elseif (self::isWhiteChar($c)) { |
||
219 | $state = self::ST_TAG_ATTRIBUTES; |
||
220 | } elseif ($state === self::ST_TAG_ATTRIBUTES && $this->isValidQName($c)) { |
||
221 | $mark = $i; // mark attribute key start |
||
222 | $state = self::ST_ATTR_KEY; |
||
223 | } else $this->raiseError("Unexpected character '$c' between attributes of < $tagname >"); |
||
224 | break; |
||
225 | |||
226 | case self::ST_COMMENT: |
||
227 | if ($c === '>' && $i > $mark+4 && substr($src, $i-2, 2) === '--') { |
||
228 | |||
229 | if (preg_match('/^-|--|-$/', substr($src, $mark +4, $i-$mark+1 -7))) { |
||
230 | $this->raiseError("Ill-formed comment. XML comments are not allowed to contain '--' or start/end with '-': ".substr($src, $mark+4, $i-$mark+1-7)); |
||
231 | } |
||
232 | |||
233 | $builder->onComment($this->checkEncoding(substr($src, $mark+4, $i-$mark+1-7))); |
||
234 | $mark = $i+1; // mark text start |
||
235 | $state = self::ST_TEXT; |
||
236 | } |
||
237 | break; |
||
238 | |||
239 | case self::ST_CDATA: |
||
240 | if ($c === '>' and substr($src, $i-2, 2) === ']]') { |
||
241 | $builder->onCDATASection($this->checkEncoding(substr($src, $mark, $i-$mark-2))); |
||
242 | $mark = $i+1; // mark text start |
||
243 | $state = self::ST_TEXT; |
||
244 | } |
||
245 | break; |
||
246 | |||
247 | View Code Duplication | case self::ST_XMLDEC: |
|
248 | if ($c === '?' && substr($src, $i, 2) === '?>') { |
||
249 | $builder->onXmlDecl($this->checkEncoding(substr($src, $mark, $i-$mark+2))); |
||
250 | $i++; // skip '>' |
||
251 | $mark = $i+1; // mark text start |
||
252 | $state = self::ST_TEXT; |
||
253 | } |
||
254 | break; |
||
255 | |||
256 | case self::ST_DOCTYPE: |
||
257 | if ($c === '[') { |
||
258 | $customDoctype = true; |
||
259 | } elseif ($customDoctype && $c === '>' && substr($src, $i-1, 2) === ']>') { |
||
260 | $customDoctype = false; |
||
261 | $builder->onDocType($this->checkEncoding(substr($src, $mark, $i-$mark+1))); |
||
262 | $mark = $i+1; // mark text start |
||
263 | $state = self::ST_TEXT; |
||
264 | } elseif (!$customDoctype && $c === '>') { |
||
265 | $customDoctype = false; |
||
266 | $builder->onDocType($this->checkEncoding(substr($src, $mark, $i-$mark+1))); |
||
267 | $mark = $i+1; // mark text start |
||
268 | $state = self::ST_TEXT; |
||
269 | } |
||
270 | break; |
||
271 | |||
272 | View Code Duplication | case self::ST_PREPROC: |
|
273 | if ($c === '>' and substr($src, $i-1, 1) === '?') { |
||
274 | $builder->onProcessingInstruction($this->checkEncoding(substr($src, $mark, $i-$mark+1))); |
||
275 | $mark = $i+1; // mark text start |
||
276 | $state = self::ST_TEXT; |
||
277 | } |
||
278 | break; |
||
279 | |||
280 | case self::ST_ATTR_KEY: |
||
281 | if ($c === '=' || self::isWhiteChar($c)) { |
||
282 | $attribute = substr($src, $mark, $i-$mark); |
||
283 | if (!$this->isValidQName($attribute)) { |
||
284 | $this->raiseError("Invalid attribute name '$attribute' in < $tagname >"); |
||
285 | } |
||
286 | if (isset($attributes[$attribute])) { |
||
287 | $this->raiseError("Attribute $attribute in < $tagname > is defined more than once"); |
||
288 | } |
||
289 | |||
290 | if ($c === '=') $state = self::ST_ATTR_VALUE; |
||
291 | else /* white char */ $state = self::ST_ATTR_EQ; |
||
292 | } elseif ($c === '/' || $c==='>') { |
||
293 | $attribute = substr($src, $mark, $i-$mark); |
||
294 | if (!$this->isValidQName($attribute)) { |
||
295 | $this->raiseError("Invalid attribute name '$attribute'"); |
||
296 | } |
||
297 | $this->raiseError("Attribute $attribute does not have value (found end of tag instead of '=')"); |
||
298 | } |
||
299 | break; |
||
300 | |||
301 | View Code Duplication | case self::ST_ATTR_EQ: |
|
302 | if ($c === '=') { |
||
303 | $state = self::ST_ATTR_VALUE; |
||
304 | } elseif (!self::isWhiteChar($c)) { |
||
305 | $this->raiseError("Attribute $attribute in < $tagname > does not have value (found character '$c' instead of '=')"); |
||
306 | } |
||
307 | break; |
||
308 | |||
309 | case self::ST_ATTR_VALUE: |
||
310 | if (self::isWhiteChar($c)) { |
||
311 | } elseif ($c === '"' or $c === '\'') { |
||
312 | $quoteStyle = $c; |
||
313 | $state = self::ST_ATTR_QUOTE; |
||
314 | $mark = $i+1; // mark attribute real value start |
||
315 | } else { |
||
316 | $this->raiseError("Value of attribute $attribute in < $tagname > is not in quotes (found character '$c' instead of quote)"); |
||
317 | } |
||
318 | break; |
||
319 | |||
320 | case self::ST_ATTR_QUOTE: |
||
321 | if ($c === $quoteStyle) { |
||
322 | $attributes[$attribute] = $this->sanitizeEscapedText($this->checkEncoding(substr($src, $mark, $i-$mark))); |
||
323 | |||
324 | // PHPTAL's code generator assumes input is escaped for double-quoted strings. Single-quoted attributes need to be converted. |
||
325 | // FIXME: it should be escaped at later stage. |
||
326 | $attributes[$attribute] = str_replace('"',""", $attributes[$attribute]); |
||
327 | $state = self::ST_TAG_BETWEEN_ATTRIBUTE; |
||
328 | } |
||
329 | break; |
||
330 | } |
||
331 | } |
||
332 | |||
333 | if ($state === self::ST_TEXT) // allows text past root node, which is in violation of XML spec |
||
334 | { |
||
335 | if ($i > $mark) { |
||
336 | $text = substr($src, $mark, $i-$mark); |
||
337 | if (!ctype_space($text)) $this->raiseError("Characters found after end of the root element (wrap document in < tal:block > to avoid this error)"); |
||
338 | } |
||
339 | } else { |
||
340 | if ($state === self::ST_ROOT) { |
||
341 | $msg = "Document does not have any tags"; |
||
342 | } else { |
||
343 | $msg = "Finished document in unexpected state: ".self::$state_names[$state]." is not finished"; |
||
344 | } |
||
345 | $this->raiseError($msg); |
||
346 | } |
||
347 | |||
348 | $builder->onDocumentEnd(); |
||
349 | } |
||
350 | catch(PHPTAL_TemplateException $e) |
||
351 | { |
||
352 | $e->hintSrcPosition($this->_file, $this->_line); |
||
353 | throw $e; |
||
354 | } |
||
355 | return $builder; |
||
356 | } |
||
357 | |||
482 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.