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
@returnannotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.