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 | 722 | public static function verify(&$context, $template) { |
|
| 39 | 722 | $template = SafeString::stripExtendedComments($template); |
|
| 40 | 722 | $context['level'] = 0; |
|
| 41 | 722 | Parser::setDelimiter($context); |
|
| 42 | |||
| 43 | 722 | while (preg_match($context['tokens']['search'], $template, $matches)) { |
|
| 44 | // Skip a token when it is slash escaped |
||
| 45 | 711 | 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 | 709 | $context['tokens']['count']++; |
|
| 56 | 709 | $V = static::token($matches, $context); |
|
| 57 | 709 | static::pushLeft($context); |
|
| 58 | 709 | if ($V) { |
|
| 59 | 670 | if (is_array($V)) { |
|
| 60 | 663 | array_push($V, $matches, $context['tokens']['partialind']); |
|
| 61 | } |
||
| 62 | 670 | static::pushToken($context, $V); |
|
| 63 | } |
||
| 64 | 709 | $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; |
|
| 65 | } |
||
| 66 | 722 | static::pushToken($context, $template); |
|
| 67 | |||
| 68 | 722 | 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 | 722 | } |
|
| 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 | 709 | 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 | 722 | 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 | 352 | protected static function pushStack(&$context, $operation, $vars) { |
|
| 113 | 352 | list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]); |
|
| 114 | 352 | $context['stack'][] = $context['currentToken'][Token::POS_INNERTAG]; |
|
| 115 | 352 | $context['stack'][] = Expression::toString($levels, $spvar, $var); |
|
| 116 | 352 | $context['stack'][] = $operation; |
|
| 117 | 352 | $context['level']++; |
|
| 118 | 352 | } |
|
| 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 | 710 | 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)), 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()), 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()), 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()), 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()), 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()), 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('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), 'elseif' => false, 'elselvl' => array()), array('test') |
||
| 165 | */ |
||
| 166 | 671 | protected static function operator($operator, &$context, &$vars) { |
|
| 223 | |||
| 224 | /** |
||
| 225 | * validate inline partial begin token |
||
| 226 | * |
||
| 227 | * @param array<string,array|string|integer> $context current compile context |
||
| 228 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 229 | * |
||
| 230 | * @return boolean|null Return true when inline partial ends |
||
| 231 | */ |
||
| 232 | 670 | protected static function inlinePartial(&$context, $vars) { |
|
| 260 | |||
| 261 | /** |
||
| 262 | * validate partial block token |
||
| 263 | * |
||
| 264 | * @param array<string,array|string|integer> $context current compile context |
||
| 265 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 266 | * |
||
| 267 | * @return boolean|null Return true when partial block ends |
||
| 268 | */ |
||
| 269 | 670 | protected static function partialBlock(&$context, $vars) { |
|
| 298 | |||
| 299 | /** |
||
| 300 | * handle else if |
||
| 301 | * |
||
| 302 | * @param array<string,array|string|integer> $context current compile context |
||
| 303 | */ |
||
| 304 | 75 | protected static function doElseIf(&$context) { |
|
| 311 | |||
| 312 | /** |
||
| 313 | * validate block begin token |
||
| 314 | * |
||
| 315 | * @param array<string,array|string|integer> $context current compile context |
||
| 316 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 317 | * |
||
| 318 | * @return boolean Return true always |
||
| 319 | */ |
||
| 320 | 255 | protected static function blockBegin(&$context, $vars) { |
|
| 337 | |||
| 338 | /** |
||
| 339 | * validate builtin helpers |
||
| 340 | * |
||
| 341 | * @param array<string,array|string|integer> $context current compile context |
||
| 342 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 343 | */ |
||
| 344 | 145 | protected static function builtin(&$context, $vars) { |
|
| 356 | |||
| 357 | /** |
||
| 358 | * validate section token |
||
| 359 | * |
||
| 360 | * @param array<string,array|string|integer> $context current compile context |
||
| 361 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 362 | * @param boolean $isEach the section is #each |
||
| 363 | * |
||
| 364 | * @return boolean Return true always |
||
| 365 | */ |
||
| 366 | 171 | protected static function section(&$context, $vars, $isEach = false) { |
|
| 377 | |||
| 378 | /** |
||
| 379 | * validate with token |
||
| 380 | * |
||
| 381 | * @param array<string,array|string|integer> $context current compile context |
||
| 382 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 383 | * |
||
| 384 | * @return boolean Return true always |
||
| 385 | */ |
||
| 386 | 31 | protected static function with(&$context, $vars) { |
|
| 390 | |||
| 391 | /** |
||
| 392 | * validate unless token |
||
| 393 | * |
||
| 394 | * @param array<string,array|string|integer> $context current compile context |
||
| 395 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 396 | * |
||
| 397 | * @return boolean Return true always |
||
| 398 | */ |
||
| 399 | 7 | protected static function unless(&$context, $vars) { |
|
| 404 | |||
| 405 | /** |
||
| 406 | * validate if token |
||
| 407 | * |
||
| 408 | * @param array<string,array|string|integer> $context current compile context |
||
| 409 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 410 | * |
||
| 411 | * @return boolean Return true always |
||
| 412 | */ |
||
| 413 | 69 | protected static function doIf(&$context, $vars) { |
|
| 418 | |||
| 419 | /** |
||
| 420 | * validate block custom helper token |
||
| 421 | * |
||
| 422 | * @param array<string,array|string|integer> $context current compile context |
||
| 423 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 424 | * @param boolean $inverted the logic will be inverted |
||
| 425 | * |
||
| 426 | * @return integer|null Return number of used custom helpers |
||
|
1 ignored issue
–
show
|
|||
| 427 | */ |
||
| 428 | 58 | protected static function blockCustomHelper(&$context, $vars, $inverted = false) { |
|
| 436 | |||
| 437 | /** |
||
| 438 | * validate inverted section |
||
| 439 | * |
||
| 440 | * @param array<string,array|string|integer> $context current compile context |
||
| 441 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 442 | * |
||
| 443 | * @return integer Return number of inverted sections |
||
|
1 ignored issue
–
show
|
|||
| 444 | */ |
||
| 445 | 38 | protected static function invertedSection(&$context, $vars) { |
|
| 448 | |||
| 449 | /** |
||
| 450 | * Return compiled PHP code for a handlebars block end token |
||
| 451 | * |
||
| 452 | * @param array<string,array|string|integer> $context current compile context |
||
| 453 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 454 | * @param string|null $match should also match to this operator |
||
| 455 | * |
||
| 456 | * @return boolean Return true |
||
| 457 | */ |
||
| 458 | 347 | protected static function blockEnd(&$context, &$vars, $match = null) { |
|
| 498 | |||
| 499 | /** |
||
| 500 | * handle delimiter change |
||
| 501 | * |
||
| 502 | * @param array<string,array|string|integer> $context current compile context |
||
| 503 | * |
||
| 504 | * @return boolean|null Return true when delimiter changed |
||
| 505 | */ |
||
| 506 | 699 | protected static function isDelimiter(&$context) { |
|
| 513 | |||
| 514 | /** |
||
| 515 | * handle raw block |
||
| 516 | * |
||
| 517 | * @param string[] $token detected handlebars {{ }} token |
||
| 518 | * @param array<string,array|string|integer> $context current compile context |
||
| 519 | * |
||
| 520 | * @return boolean|null Return true when in rawblock mode |
||
| 521 | */ |
||
| 522 | 709 | protected static function rawblock(&$token, &$context) { |
|
| 552 | |||
| 553 | /** |
||
| 554 | * handle comment |
||
| 555 | * |
||
| 556 | * @param string[] $token detected handlebars {{ }} token |
||
| 557 | * @param array<string,array|string|integer> $context current compile context |
||
| 558 | * |
||
| 559 | * @return boolean|null Return true when is comment |
||
| 560 | */ |
||
| 561 | 690 | protected static function comment(&$token, &$context) { |
|
| 567 | |||
| 568 | /** |
||
| 569 | * Collect handlebars usage information, detect template error. |
||
| 570 | * |
||
| 571 | * @param string[] $token detected handlebars {{ }} token |
||
| 572 | * @param array<string,array|string|integer> $context current compile context |
||
| 573 | */ |
||
| 574 | 709 | protected static function token(&$token, &$context) { |
|
| 649 | |||
| 650 | /** |
||
| 651 | * Return 1 or larger number when else token detected |
||
| 652 | * |
||
| 653 | * @param array<string,array|string|integer> $context current compile context |
||
| 654 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 655 | * |
||
| 656 | * @return integer Return 1 or larger number when else token detected |
||
|
1 ignored issue
–
show
|
|||
| 657 | */ |
||
| 658 | 49 | protected static function doElse(&$context, $vars) { |
|
| 672 | |||
| 673 | /** |
||
| 674 | * Return true when this is {{log ...}} |
||
| 675 | * |
||
| 676 | * @param array<string,array|string|integer> $context current compile context |
||
| 677 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 678 | * |
||
| 679 | * @return boolean|null Return true when it is custom helper |
||
| 680 | */ |
||
| 681 | 349 | public static function log(&$context, $vars) { |
|
| 692 | |||
| 693 | /** |
||
| 694 | * Return true when this is {{lookup ...}} |
||
| 695 | * |
||
| 696 | * @param array<string,array|string|integer> $context current compile context |
||
| 697 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 698 | * |
||
| 699 | * @return boolean|null Return true when it is custom helper |
||
| 700 | */ |
||
| 701 | 349 | public static function lookup(&$context, $vars) { |
|
| 714 | |||
| 715 | /** |
||
| 716 | * Return true when the name is listed in helper table |
||
| 717 | * |
||
| 718 | * @param array<string,array|string|integer> $context current compile context |
||
| 719 | * @param string $name token name |
||
| 720 | * |
||
| 721 | * @return boolean Return true when it is custom helper |
||
| 722 | */ |
||
| 723 | 466 | public static function helper(&$context, $name) { |
|
| 731 | |||
| 732 | /** |
||
| 733 | * detect for block custom helper |
||
| 734 | * |
||
| 735 | * @param array<string,array|string|integer> $context current compile context |
||
| 736 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 737 | * |
||
| 738 | * @return boolean|null Return true when this token is block custom helper |
||
| 739 | */ |
||
| 740 | 336 | protected static function isBlockHelper($context, $vars) { |
|
| 751 | |||
| 752 | /** |
||
| 753 | * validate inline partial |
||
| 754 | * |
||
| 755 | * @param array<string,array|string|integer> $context current compile context |
||
| 756 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 757 | * |
||
| 758 | * @return boolean Return true always |
||
| 759 | */ |
||
| 760 | 13 | protected static function inline(&$context, $vars) { |
|
| 772 | |||
| 773 | /** |
||
| 774 | * validate partial |
||
| 775 | * |
||
| 776 | * @param array<string,array|string|integer> $context current compile context |
||
| 777 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
| 778 | * |
||
| 779 | * @return integer|boolean Return 1 or larger number for runtime partial, return true for other case |
||
|
1 ignored issue
–
show
|
|||
| 780 | */ |
||
| 781 | 93 | protected static function partial(&$context, $vars) { |
|
| 803 | |||
| 804 | /** |
||
| 805 | * Modify $token when spacing rules matched. |
||
| 806 | * |
||
| 807 | * @param array<string> $token detected handlebars {{ }} token |
||
| 808 | * @param array<string,array|string|integer> $context current compile context |
||
| 809 | * @param boolean $nost do not do stand alone logic |
||
| 810 | * |
||
| 811 | * @return string|null Return compiled code segment for the token |
||
| 812 | */ |
||
| 813 | 699 | protected static function spacing(&$token, &$context, $nost = false) { |
|
| 864 | } |
||
| 865 | |||
| 866 |
This check compares the return type specified in the
@returnannotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.