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 | 729 | public static function verify(&$context, $template) { |
|
39 | 729 | $template = SafeString::stripExtendedComments($template); |
|
40 | 729 | $context['level'] = 0; |
|
41 | 729 | Parser::setDelimiter($context); |
|
42 | |||
43 | 729 | while (preg_match($context['tokens']['search'], $template, $matches)) { |
|
44 | // Skip a token when it is slash escaped |
||
45 | 718 | 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 | 716 | $context['tokens']['count']++; |
|
56 | 716 | $V = static::token($matches, $context); |
|
57 | 716 | static::pushLeft($context); |
|
58 | 716 | if ($V) { |
|
59 | 677 | if (is_array($V)) { |
|
60 | 670 | array_push($V, $matches, $context['tokens']['partialind']); |
|
61 | } |
||
62 | 677 | static::pushToken($context, $V); |
|
63 | } |
||
64 | 716 | $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; |
|
65 | } |
||
66 | 729 | static::pushToken($context, $template); |
|
67 | |||
68 | 729 | if ($context['level'] > 0) { |
|
69 | 6 | array_pop($context['stack']); |
|
70 | 6 | array_pop($context['stack']); |
|
71 | 6 | $token = array_pop($context['stack']); |
|
72 | 6 | $context['error'][] = 'Unclosed token ' . ($context['rawblock'] ? "{{{{{$token}}}}}" : "{{#{$token}}}") . ' !!'; |
|
73 | } |
||
74 | 729 | } |
|
75 | |||
76 | /** |
||
77 | * push left string of current token and clear it |
||
78 | * |
||
79 | * @param array<string,array|string|integer> $context Current context |
||
80 | */ |
||
81 | 716 | protected static function pushLeft(&$context) { |
|
85 | |||
86 | /** |
||
87 | * push a token into the stack when it is not empty string |
||
88 | * |
||
89 | * @param array<string,array|string|integer> $context Current context |
||
90 | * @param string|array $token a parsed token or a string |
||
91 | */ |
||
92 | 729 | protected static function pushToken(&$context, $token) { |
|
104 | |||
105 | /** |
||
106 | * push current token into the section stack |
||
107 | * |
||
108 | * @param array<string,array|string|integer> $context Current context |
||
109 | * @param string $operation operation string |
||
110 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
111 | */ |
||
112 | 355 | protected static function pushStack(&$context, $operation, $vars) { |
|
119 | |||
120 | /** |
||
121 | * Verify delimiters and operators |
||
122 | * |
||
123 | * @param string[] $token detected handlebars {{ }} token |
||
124 | * @param array<string,array|string|integer> $context current compile context |
||
125 | * |
||
126 | * @return boolean|null Return true when invalid |
||
127 | * |
||
128 | * @expect null when input array_fill(0, 11, ''), array() |
||
129 | * @expect null when input array(0, 0, 0, 0, 0, '{{', '#', '...', '}}'), array() |
||
130 | * @expect true when input array(0, 0, 0, 0, 0, '{', '#', '...', '}'), array() |
||
131 | */ |
||
132 | 717 | protected static function delimiter($token, &$context) { |
|
144 | |||
145 | /** |
||
146 | * Verify operators |
||
147 | * |
||
148 | * @param string $operator the operator string |
||
149 | * @param array<string,array|string|integer> $context current compile context |
||
150 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
151 | * |
||
152 | * @return boolean|integer|null Return true when invalid or detected |
||
1 ignored issue
–
show
|
|||
153 | * |
||
154 | * @expect null when input '', array(), array() |
||
155 | * @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), 'helperresolver' => 0), array(array('foo')) |
||
156 | * @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()) |
||
157 | * @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), 'elseif' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('x')) |
||
158 | * @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), 'elseif' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('if')) |
||
159 | * @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), 'elseif' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('with')) |
||
160 | * @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), 'elseif' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('each')) |
||
161 | * @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), 'elseif' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('unless')) |
||
162 | * @expect 9 when input '#', array('helpers' => array('abc' => ''), 'usedFeature' => array('helper' => 8), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0), 'elseif' => false, 'elselvl' => array()), array(array('abc')) |
||
163 | * @expect 11 when input '#', array('helpers' => array('abc' => ''), 'usedFeature' => array('helper' => 10), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0), 'elseif' => false, 'elselvl' => array()), array(array('abc')) |
||
164 | * @expect true when input '>', array('partialresolver' => false, 'usedFeature' => array('partial' => 7), 'level' => 0, 'flags' => array('skippartial' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0), 'elseif' => false, 'elselvl' => array()), array('test') |
||
165 | */ |
||
166 | 678 | protected static function operator($operator, &$context, &$vars) { |
|
228 | |||
229 | /** |
||
230 | * validate inline partial begin token |
||
231 | * |
||
232 | * @param array<string,array|string|integer> $context current compile context |
||
233 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
234 | * |
||
235 | * @return boolean|null Return true when inline partial ends |
||
236 | */ |
||
237 | 677 | protected static function inlinePartial(&$context, $vars) { |
|
265 | |||
266 | /** |
||
267 | * validate partial block token |
||
268 | * |
||
269 | * @param array<string,array|string|integer> $context current compile context |
||
270 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
271 | * |
||
272 | * @return boolean|null Return true when partial block ends |
||
273 | */ |
||
274 | 677 | protected static function partialBlock(&$context, $vars) { |
|
306 | |||
307 | /** |
||
308 | * handle else if |
||
309 | * |
||
310 | * @param array<string,array|string|integer> $context current compile context |
||
311 | */ |
||
312 | 76 | protected static function doElseIf(&$context) { |
|
319 | |||
320 | /** |
||
321 | * validate block begin token |
||
322 | * |
||
323 | * @param array<string,array|string|integer> $context current compile context |
||
324 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
325 | * |
||
326 | * @return boolean Return true always |
||
327 | */ |
||
328 | 256 | protected static function blockBegin(&$context, $vars) { |
|
345 | |||
346 | /** |
||
347 | * validate builtin helpers |
||
348 | * |
||
349 | * @param array<string,array|string|integer> $context current compile context |
||
350 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
351 | */ |
||
352 | 146 | protected static function builtin(&$context, $vars) { |
|
364 | |||
365 | /** |
||
366 | * validate section token |
||
367 | * |
||
368 | * @param array<string,array|string|integer> $context current compile context |
||
369 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
370 | * @param boolean $isEach the section is #each |
||
371 | * |
||
372 | * @return boolean Return true always |
||
373 | */ |
||
374 | 171 | protected static function section(&$context, $vars, $isEach = false) { |
|
385 | |||
386 | /** |
||
387 | * validate with token |
||
388 | * |
||
389 | * @param array<string,array|string|integer> $context current compile context |
||
390 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
391 | * |
||
392 | * @return boolean Return true always |
||
393 | */ |
||
394 | 30 | protected static function with(&$context, $vars) { |
|
398 | |||
399 | /** |
||
400 | * validate unless token |
||
401 | * |
||
402 | * @param array<string,array|string|integer> $context current compile context |
||
403 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
404 | * |
||
405 | * @return boolean Return true always |
||
406 | */ |
||
407 | 7 | protected static function unless(&$context, $vars) { |
|
412 | |||
413 | /** |
||
414 | * validate if token |
||
415 | * |
||
416 | * @param array<string,array|string|integer> $context current compile context |
||
417 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
418 | * |
||
419 | * @return boolean Return true always |
||
420 | */ |
||
421 | 70 | protected static function doIf(&$context, $vars) { |
|
426 | |||
427 | /** |
||
428 | * validate block custom helper token |
||
429 | * |
||
430 | * @param array<string,array|string|integer> $context current compile context |
||
431 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
432 | * @param boolean $inverted the logic will be inverted |
||
433 | * |
||
434 | * @return integer|null Return number of used custom helpers |
||
1 ignored issue
–
show
|
|||
435 | */ |
||
436 | 59 | protected static function blockCustomHelper(&$context, $vars, $inverted = false) { |
|
443 | |||
444 | /** |
||
445 | * validate inverted section |
||
446 | * |
||
447 | * @param array<string,array|string|integer> $context current compile context |
||
448 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
449 | * |
||
450 | * @return integer Return number of inverted sections |
||
1 ignored issue
–
show
|
|||
451 | */ |
||
452 | 38 | protected static function invertedSection(&$context, $vars) { |
|
455 | |||
456 | /** |
||
457 | * Return compiled PHP code for a handlebars block end token |
||
458 | * |
||
459 | * @param array<string,array|string|integer> $context current compile context |
||
460 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
461 | * @param string|null $match should also match to this operator |
||
462 | * |
||
463 | * @return boolean Return true |
||
464 | */ |
||
465 | 350 | protected static function blockEnd(&$context, &$vars, $match = null) { |
|
505 | |||
506 | /** |
||
507 | * handle delimiter change |
||
508 | * |
||
509 | * @param array<string,array|string|integer> $context current compile context |
||
510 | * |
||
511 | * @return boolean|null Return true when delimiter changed |
||
512 | */ |
||
513 | 706 | protected static function isDelimiter(&$context) { |
|
520 | |||
521 | /** |
||
522 | * handle raw block |
||
523 | * |
||
524 | * @param string[] $token detected handlebars {{ }} token |
||
525 | * @param array<string,array|string|integer> $context current compile context |
||
526 | * |
||
527 | * @return boolean|null Return true when in rawblock mode |
||
528 | */ |
||
529 | 716 | protected static function rawblock(&$token, &$context) { |
|
559 | |||
560 | /** |
||
561 | * handle comment |
||
562 | * |
||
563 | * @param string[] $token detected handlebars {{ }} token |
||
564 | * @param array<string,array|string|integer> $context current compile context |
||
565 | * |
||
566 | * @return boolean|null Return true when is comment |
||
567 | */ |
||
568 | 697 | protected static function comment(&$token, &$context) { |
|
574 | |||
575 | /** |
||
576 | * Collect handlebars usage information, detect template error. |
||
577 | * |
||
578 | * @param string[] $token detected handlebars {{ }} token |
||
579 | * @param array<string,array|string|integer> $context current compile context |
||
580 | */ |
||
581 | 716 | protected static function token(&$token, &$context) { |
|
656 | |||
657 | /** |
||
658 | * Return 1 or larger number when else token detected |
||
659 | * |
||
660 | * @param array<string,array|string|integer> $context current compile context |
||
661 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
662 | * |
||
663 | * @return integer Return 1 or larger number when else token detected |
||
1 ignored issue
–
show
|
|||
664 | */ |
||
665 | 50 | protected static function doElse(&$context, $vars) { |
|
679 | |||
680 | /** |
||
681 | * Return true when this is {{log ...}} |
||
682 | * |
||
683 | * @param array<string,array|string|integer> $context current compile context |
||
684 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
685 | * |
||
686 | * @return boolean|null Return true when it is custom helper |
||
687 | */ |
||
688 | 350 | public static function log(&$context, $vars) { |
|
699 | |||
700 | /** |
||
701 | * Return true when this is {{lookup ...}} |
||
702 | * |
||
703 | * @param array<string,array|string|integer> $context current compile context |
||
704 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
705 | * |
||
706 | * @return boolean|null Return true when it is custom helper |
||
707 | */ |
||
708 | 350 | public static function lookup(&$context, $vars) { |
|
721 | |||
722 | /** |
||
723 | * Return true when the name is listed in helper table |
||
724 | * |
||
725 | * @param array<string,array|string|integer> $context current compile context |
||
726 | * @param string $name token name |
||
727 | * |
||
728 | * @return boolean Return true when it is custom helper |
||
729 | */ |
||
730 | 468 | public static function helper(&$context, $name) { |
|
738 | |||
739 | /** |
||
740 | * use helperresolver to resolve helper, return true when helper founded |
||
741 | * |
||
742 | * @param array<string,array|string|integer> $context Current context of compiler progress. |
||
743 | * @param string $name helper name |
||
744 | * |
||
745 | * @return string|null $content helper function name or callable |
||
1 ignored issue
–
show
|
|||
746 | */ |
||
747 | 619 | public static function resolveHelper(&$context, &$name) { |
|
760 | |||
761 | /** |
||
762 | * detect for block custom helper |
||
763 | * |
||
764 | * @param array<string,array|string|integer> $context current compile context |
||
765 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
766 | * |
||
767 | * @return boolean|null Return true when this token is block custom helper |
||
768 | */ |
||
769 | 338 | protected static function isBlockHelper($context, $vars) { |
|
780 | |||
781 | /** |
||
782 | * validate inline partial |
||
783 | * |
||
784 | * @param array<string,array|string|integer> $context current compile context |
||
785 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
786 | * |
||
787 | * @return boolean Return true always |
||
788 | */ |
||
789 | 13 | protected static function inline(&$context, $vars) { |
|
801 | |||
802 | /** |
||
803 | * validate partial |
||
804 | * |
||
805 | * @param array<string,array|string|integer> $context current compile context |
||
806 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
807 | * |
||
808 | * @return integer|boolean Return 1 or larger number for runtime partial, return true for other case |
||
1 ignored issue
–
show
|
|||
809 | */ |
||
810 | 95 | protected static function partial(&$context, $vars) { |
|
832 | |||
833 | /** |
||
834 | * Modify $token when spacing rules matched. |
||
835 | * |
||
836 | * @param array<string> $token detected handlebars {{ }} token |
||
837 | * @param array<string,array|string|integer> $context current compile context |
||
838 | * @param boolean $nost do not do stand alone logic |
||
839 | * |
||
840 | * @return string|null Return compiled code segment for the token |
||
841 | */ |
||
842 | 706 | protected static function spacing(&$token, &$context, $nost = false) { |
|
893 | } |
||
894 | |||
895 |
This check compares the return type specified in the
@return
annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.