Complex classes like Validator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Validator, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Validator { |
||
32 | /** |
||
33 | * Verify template |
||
34 | * |
||
35 | * @param array<string,array|string|integer> $context Current context |
||
36 | * @param string $template handlebars template |
||
37 | */ |
||
38 | 702 | public static function verify(&$context, $template) { |
|
39 | 702 | $template = SafeString::stripExtendedComments($template); |
|
40 | 702 | $context['level'] = 0; |
|
41 | 702 | Parser::setDelimiter($context); |
|
42 | |||
43 | 702 | while (preg_match($context['tokens']['search'], $template, $matches)) { |
|
44 | // Skip a token when it is slash escaped |
||
45 | 691 | if ($context['flags']['slash'] && ($matches[Token::POS_LSPACE] === '') && preg_match('/^(.*?)(\\\\+)$/s', $matches[Token::POS_LOTHER], $escmatch)) { |
|
46 | 4 | if (strlen($escmatch[2]) % 4) { |
|
47 | 2 | static::pushToken($context, substr($matches[Token::POS_LOTHER], 0, -2) . $context['tokens']['startchar']); |
|
48 | 2 | $matches[Token::POS_BEGINTAG] = substr($matches[Token::POS_BEGINTAG], 1); |
|
49 | 2 | $template = implode('', array_slice($matches, Token::POS_BEGINTAG)); |
|
50 | 2 | continue; |
|
51 | } else { |
||
52 | 2 | $matches[Token::POS_LOTHER] = $escmatch[1] . str_repeat('\\', strlen($escmatch[2]) / 2); |
|
53 | } |
||
54 | } |
||
55 | 689 | $context['tokens']['count']++; |
|
56 | 689 | $V = static::token($matches, $context); |
|
57 | 689 | static::pushToken($context, $matches[Token::POS_LOTHER]); |
|
58 | 689 | static::pushToken($context, $matches[Token::POS_LSPACE]); |
|
59 | 689 | if ($V) { |
|
60 | 650 | if (is_array($V)) { |
|
61 | 643 | array_push($V, $matches, $context['tokens']['partialind']); |
|
62 | } |
||
63 | 650 | static::pushToken($context, $V); |
|
64 | } |
||
65 | 689 | $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; |
|
66 | } |
||
67 | 702 | static::pushToken($context, $template); |
|
68 | |||
69 | 702 | if ($context['level'] > 0) { |
|
70 | 6 | array_pop($context['stack']); |
|
71 | 6 | array_pop($context['stack']); |
|
72 | 6 | $token = array_pop($context['stack']); |
|
73 | 6 | $context['error'][] = 'Unclosed token ' . ($context['rawblock'] ? "{{{{{$token}}}}}" : "{{#{$token}}}") . ' !!'; |
|
74 | } |
||
75 | 702 | } |
|
76 | |||
77 | /** |
||
78 | * push a token into the stack when it is not empty string |
||
79 | * |
||
80 | * @param array<string,array|string|integer> $context Current context |
||
81 | * @param string|array $token a parsed token or a string |
||
82 | */ |
||
83 | 702 | protected static function pushToken(&$context, $token) { |
|
84 | 702 | if ($token === '') { |
|
85 | 647 | return; |
|
86 | } |
||
87 | 691 | if (is_string($token)) { |
|
88 | 466 | if (is_string(end($context['parsed'][0]))) { |
|
89 | 223 | $context['parsed'][0][key($context['parsed'][0])] .= $token; |
|
90 | 223 | return; |
|
91 | } |
||
92 | } |
||
93 | 691 | $context['parsed'][0][] = $token; |
|
94 | 691 | } |
|
95 | |||
96 | /** |
||
97 | * push current token into the section stack |
||
98 | * |
||
99 | * @param array<string,array|string|integer> $context Current context |
||
100 | * @param string $operation operation string |
||
101 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
102 | */ |
||
103 | 337 | protected static function pushStack(&$context, $operation, $vars) { |
|
110 | |||
111 | /** |
||
112 | * Verify delimiters and operators |
||
113 | * |
||
114 | * @param string[] $token detected handlebars {{ }} token |
||
115 | * @param array<string,array|string|integer> $context current compile context |
||
116 | * |
||
117 | * @return boolean|null Return true when invalid |
||
118 | * |
||
119 | * @expect null when input array_fill(0, 11, ''), array() |
||
120 | * @expect null when input array(0, 0, 0, 0, 0, '{{', '#', '...', '}}'), array() |
||
121 | * @expect true when input array(0, 0, 0, 0, 0, '{', '#', '...', '}'), array() |
||
122 | */ |
||
123 | 690 | protected static function delimiter($token, &$context) { |
|
135 | |||
136 | /** |
||
137 | * Verify operators |
||
138 | * |
||
139 | * @param string $operator the operator string |
||
140 | * @param array<string,array|string|integer> $context current compile context |
||
141 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
142 | * |
||
143 | * @return boolean|integer|null Return true when invalid or detected |
||
144 | * |
||
145 | * @expect null when input '', array(), array() |
||
146 | * @expect 2 when input '^', array('usedFeature' => array('isec' => 1), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('foo')) |
||
147 | * @expect true when input '/', array('stack' => array('[with]', '#'), 'level' => 1, 'currentToken' => array(0,0,0,0,0,0,0,'with'), 'flags' => array('nohbh' => 0)), array(array()) |
||
148 | * @expect 4 when input '#', array('usedFeature' => array('sec' => 3), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('x')) |
||
149 | * @expect 5 when input '#', array('usedFeature' => array('if' => 4), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('if')) |
||
150 | * @expect 6 when input '#', array('usedFeature' => array('with' => 5), 'level' => 0, 'flags' => array('nohbh' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0)), array(array('with')) |
||
151 | * @expect 7 when input '#', array('usedFeature' => array('each' => 6), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('each')) |
||
152 | * @expect 8 when input '#', array('usedFeature' => array('unless' => 7), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('unless')) |
||
153 | * @expect 9 when input '#', array('blockhelpers' => array('abc' => ''), 'usedFeature' => array('bhelper' => 8), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('abc')) |
||
154 | * @expect 11 when input '#', array('hbhelpers' => array('abc' => ''), 'usedFeature' => array('hbhelper' => 10), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('abc')) |
||
155 | * @expect true when input '>', array('basedir' => array('.'), 'fileext' => array('.tmpl'), 'usedFeature' => array('partial' => 7), 'level' => 0, 'flags' => array('skippartial' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0)), array('test') |
||
156 | */ |
||
157 | 651 | protected static function operator($operator, &$context, &$vars) { |
|
209 | |||
210 | /** |
||
211 | * validate inline partial begin token |
||
212 | 650 | * |
|
213 | 650 | * @param array<string,array|string|integer> $context current compile context |
|
214 | 8 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
215 | 8 | * |
|
216 | 8 | * @return boolean Return true when inline partial ends |
|
217 | 8 | */ |
|
218 | 8 | protected static function inlinePartial(&$context, $vars) { |
|
242 | |||
243 | /** |
||
244 | * validate partial block token |
||
245 | * |
||
246 | * @param array<string,array|string|integer> $context current compile context |
||
247 | 249 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
248 | 249 | * |
|
249 | 5 | * @return boolean Return true always |
|
1 ignored issue
–
show
|
|||
250 | 28 | */ |
|
251 | 5 | protected static function partialBlock(&$context, $vars) { |
|
278 | 136 | ||
279 | 136 | /** |
|
280 | * validate block begin token |
||
281 | * |
||
282 | * @param array<string,array|string|integer> $context current compile context |
||
283 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
284 | * |
||
285 | * @return boolean Return true always |
||
286 | */ |
||
287 | protected static function blockBegin(&$context, $vars) { |
||
301 | |||
302 | /** |
||
303 | * validate builtin helpers |
||
304 | * |
||
305 | * @param array<string,array|string|integer> $context current compile context |
||
306 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
307 | */ |
||
308 | protected static function builtin(&$context, $vars) { |
||
320 | |||
321 | /** |
||
322 | * validate section token |
||
323 | 6 | * |
|
324 | 6 | * @param array<string,array|string|integer> $context current compile context |
|
325 | 6 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
326 | * @param boolean $isEach the section is #each |
||
327 | * |
||
328 | * @return boolean Return true always |
||
329 | */ |
||
330 | protected static function section(&$context, $vars, $isEach = false) { |
||
341 | |||
342 | /** |
||
343 | * validate with token |
||
344 | * |
||
345 | * @param array<string,array|string|integer> $context current compile context |
||
346 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
347 | * |
||
348 | * @return boolean Return true always |
||
349 | */ |
||
350 | 61 | protected static function with(&$context, $vars) { |
|
354 | 58 | ||
355 | /** |
||
356 | * validate unless token |
||
357 | * |
||
358 | 3 | * @param array<string,array|string|integer> $context current compile context |
|
359 | 3 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
360 | * |
||
361 | * @return boolean Return true always |
||
362 | */ |
||
363 | protected static function unless(&$context, $vars) { |
||
367 | |||
368 | /** |
||
369 | * validate if token |
||
370 | * |
||
371 | * @param array<string,array|string|integer> $context current compile context |
||
372 | 38 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
373 | 38 | * |
|
374 | * @return boolean Return true always |
||
375 | */ |
||
376 | protected static function doIf(&$context, $vars) { |
||
380 | |||
381 | /** |
||
382 | * validate block custom helper token |
||
383 | * |
||
384 | 332 | * @param array<string,array|string|integer> $context current compile context |
|
385 | 332 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
386 | 332 | * @param boolean $inverted the logic will be inverted |
|
387 | 332 | * |
|
388 | 332 | * @return string|null Return compiled code segment for the token |
|
1 ignored issue
–
show
|
|||
389 | 332 | */ |
|
390 | 313 | protected static function blockCustomHelper(&$context, $vars, $inverted = false) { |
|
403 | 1 | ||
404 | 312 | /** |
|
405 | 312 | * validate inverted section |
|
406 | 312 | * |
|
407 | 2 | * @param array<string,array|string|integer> $context current compile context |
|
408 | 2 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
409 | * |
||
410 | 310 | * @return integer Return number of inverted sections |
|
1 ignored issue
–
show
|
|||
411 | 38 | */ |
|
412 | protected static function invertedSection(&$context, $vars) { |
||
415 | 1 | ||
416 | 1 | /** |
|
417 | * Return compiled PHP code for a handlebars block end token |
||
418 | * |
||
419 | * @param array<string,array|string|integer> $context current compile context |
||
420 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
421 | * |
||
422 | * @return boolean Return true |
||
423 | */ |
||
424 | protected static function blockEnd(&$context, $vars) { |
||
460 | 4 | ||
461 | 4 | /** |
|
462 | * handle delimiter change |
||
463 | 7 | * |
|
464 | 1 | * @param array<string,array|string|integer> $context current compile context |
|
465 | * |
||
466 | 7 | * @return boolean|null Return true when delimiter changed |
|
467 | 7 | */ |
|
468 | 7 | protected static function isDelimiter(&$context) { |
|
475 | |||
476 | /** |
||
477 | * handle raw block |
||
478 | * |
||
479 | * @param string[] $token detected handlebars {{ }} token |
||
480 | * @param array<string,array|string|integer> $context current compile context |
||
481 | * |
||
482 | 670 | * @return boolean|null Return true when in rawblock mode |
|
483 | 670 | */ |
|
484 | 25 | protected static function rawblock(&$token, &$context) { |
|
514 | |||
515 | /** |
||
516 | 650 | * handle comment |
|
517 | * |
||
518 | 650 | * @param string[] $token detected handlebars {{ }} token |
|
519 | 8 | * @param array<string,array|string|integer> $context current compile context |
|
520 | 8 | * |
|
521 | 8 | * @return boolean|null Return true when is comment |
|
522 | */ |
||
523 | protected static function comment(&$token, &$context) { |
||
529 | |||
530 | /** |
||
531 | 506 | * Collect handlebars usage information, detect template error. |
|
532 | 6 | * |
|
533 | * @param string[] $token detected handlebars {{ }} token |
||
534 | * @param array<string,array|string|integer> $context current compile context |
||
535 | 500 | */ |
|
536 | 1 | protected static function token(&$token, &$context) { |
|
602 | |||
603 | /** |
||
604 | * Return 1 or larger number when else token detected |
||
605 | 475 | * |
|
606 | 475 | * @param array<string,array|string|integer> $context current compile context |
|
607 | 102 | * |
|
608 | 102 | * @return integer Return 1 or larger number when else token detected |
|
1 ignored issue
–
show
|
|||
609 | */ |
||
610 | protected static function doElse(&$context) { |
||
616 | 360 | ||
617 | /** |
||
618 | * Return true whe the name is listed in helper table |
||
619 | * |
||
620 | * @param array<string,array|string|integer> $context current compile context |
||
621 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
622 | * |
||
623 | * @return boolean Return true when it is custom helper |
||
624 | */ |
||
625 | public static function lookup(&$context, $vars) { |
||
638 | |||
639 | /** |
||
640 | * Return true when the name is listed in helper table |
||
641 | * |
||
642 | * @param array<string,array|string|integer> $context current compile context |
||
643 | * @param string $name token name |
||
644 | * |
||
645 | * @return boolean Return true when it is custom helper |
||
646 | */ |
||
647 | 79 | public static function helper(&$context, $name) { |
|
660 | 74 | ||
661 | 9 | /** |
|
662 | 9 | * detect for block custom helper |
|
663 | 1 | * |
|
664 | * @param array<string,array|string|integer> $context current compile context |
||
665 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
666 | * |
||
667 | 74 | * @return boolean|null Return true when this token is block custom helper |
|
668 | */ |
||
669 | protected static function isBlockHelper($context, $vars) { |
||
680 | |||
681 | 679 | /** |
|
682 | 679 | * validate inline partial |
|
683 | * |
||
684 | 679 | * @param array<string,array|string|integer> $context current compile context |
|
685 | 679 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
|
686 | * |
||
687 | 679 | * @return boolean Return true always |
|
1 ignored issue
–
show
|
|||
688 | 679 | */ |
|
689 | protected static function inline(&$context, $vars) { |
||
700 | 194 | ||
701 | /** |
||
702 | * validate partial |
||
703 | 679 | * |
|
704 | 325 | * @param array<string,array|string|integer> $context current compile context |
|
705 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
706 | 679 | * |
|
707 | 121 | * @return integer|true Return 1 or larger number for runtime partial, return true for other case |
|
1 ignored issue
–
show
|
|||
708 | 679 | */ |
|
709 | protected static function partial(&$context, $vars) { |
||
731 | |||
732 | /** |
||
733 | * Modify $token when spacing rules matched. |
||
734 | * |
||
735 | * @param array<string> $token detected handlebars {{ }} token |
||
736 | * @param array<string,array|string|integer> $context current compile context |
||
737 | * @param boolean $nost do not do stand alone logic |
||
738 | * |
||
739 | * @return string|null Return compiled code segment for the token |
||
740 | */ |
||
741 | protected static function spacing(&$token, &$context, $nost = false) { |
||
792 | } |
||
793 | |||
794 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.