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 | 727 |     public static function verify(&$context, $template) { | 
            |
| 39 | 727 | $template = SafeString::stripExtendedComments($template);  | 
            |
| 40 | 727 | $context['level'] = 0;  | 
            |
| 41 | 727 | Parser::setDelimiter($context);  | 
            |
| 42 | |||
| 43 | 727 |         while (preg_match($context['tokens']['search'], $template, $matches)) { | 
            |
| 44 | // Skip a token when it is slash escaped  | 
            ||
| 45 | 716 |             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 | 714 | $context['tokens']['count']++;  | 
            |
| 56 | 714 | $V = static::token($matches, $context);  | 
            |
| 57 | 714 | static::pushLeft($context);  | 
            |
| 58 | 714 |             if ($V) { | 
            |
| 59 | 675 |                 if (is_array($V)) { | 
            |
| 60 | 668 | array_push($V, $matches, $context['tokens']['partialind']);  | 
            |
| 61 | }  | 
            ||
| 62 | 675 | static::pushToken($context, $V);  | 
            |
| 63 | }  | 
            ||
| 64 | 714 |             $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; | 
            |
| 65 | }  | 
            ||
| 66 | 727 | static::pushToken($context, $template);  | 
            |
| 67 | |||
| 68 | 727 |         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 | 727 | }  | 
            |
| 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 | 714 |     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 | 727 |     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 | 354 |     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 | 715 |     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('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 | 676 |     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 | 675 |     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 | 675 |     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 | 58 |     protected static function blockCustomHelper(&$context, $vars, $inverted = false) { | 
            |
| 444 | |||
| 445 | /**  | 
            ||
| 446 | * validate inverted section  | 
            ||
| 447 | *  | 
            ||
| 448 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 449 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 450 | *  | 
            ||
| 451 | * @return integer Return number of inverted sections  | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 452 | */  | 
            ||
| 453 | 38 |     protected static function invertedSection(&$context, $vars) { | 
            |
| 456 | |||
| 457 | /**  | 
            ||
| 458 | * Return compiled PHP code for a handlebars block end token  | 
            ||
| 459 | *  | 
            ||
| 460 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 461 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 462 | * @param string|null $match should also match to this operator  | 
            ||
| 463 | *  | 
            ||
| 464 | * @return boolean Return true  | 
            ||
| 465 | */  | 
            ||
| 466 | 349 |     protected static function blockEnd(&$context, &$vars, $match = null) { | 
            |
| 506 | |||
| 507 | /**  | 
            ||
| 508 | * handle delimiter change  | 
            ||
| 509 | *  | 
            ||
| 510 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 511 | *  | 
            ||
| 512 | * @return boolean|null Return true when delimiter changed  | 
            ||
| 513 | */  | 
            ||
| 514 | 704 |     protected static function isDelimiter(&$context) { | 
            |
| 521 | |||
| 522 | /**  | 
            ||
| 523 | * handle raw block  | 
            ||
| 524 | *  | 
            ||
| 525 |      * @param string[] $token detected handlebars {{ }} token | 
            ||
| 526 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 527 | *  | 
            ||
| 528 | * @return boolean|null Return true when in rawblock mode  | 
            ||
| 529 | */  | 
            ||
| 530 | 714 |     protected static function rawblock(&$token, &$context) { | 
            |
| 560 | |||
| 561 | /**  | 
            ||
| 562 | * handle comment  | 
            ||
| 563 | *  | 
            ||
| 564 |      * @param string[] $token detected handlebars {{ }} token | 
            ||
| 565 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 566 | *  | 
            ||
| 567 | * @return boolean|null Return true when is comment  | 
            ||
| 568 | */  | 
            ||
| 569 | 695 |     protected static function comment(&$token, &$context) { | 
            |
| 575 | |||
| 576 | /**  | 
            ||
| 577 | * Collect handlebars usage information, detect template error.  | 
            ||
| 578 | *  | 
            ||
| 579 |      * @param string[] $token detected handlebars {{ }} token | 
            ||
| 580 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 581 | */  | 
            ||
| 582 | 714 |     protected static function token(&$token, &$context) { | 
            |
| 657 | |||
| 658 | /**  | 
            ||
| 659 | * Return 1 or larger number when else token detected  | 
            ||
| 660 | *  | 
            ||
| 661 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 662 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 663 | *  | 
            ||
| 664 | * @return integer Return 1 or larger number when else token detected  | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 665 | */  | 
            ||
| 666 | 50 |     protected static function doElse(&$context, $vars) { | 
            |
| 680 | |||
| 681 | /**  | 
            ||
| 682 |      * Return true when this is {{log ...}} | 
            ||
| 683 | *  | 
            ||
| 684 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 685 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 686 | *  | 
            ||
| 687 | * @return boolean|null Return true when it is custom helper  | 
            ||
| 688 | */  | 
            ||
| 689 | 350 |     public static function log(&$context, $vars) { | 
            |
| 700 | |||
| 701 | /**  | 
            ||
| 702 |      * Return true when this is {{lookup ...}} | 
            ||
| 703 | *  | 
            ||
| 704 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 705 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 706 | *  | 
            ||
| 707 | * @return boolean|null Return true when it is custom helper  | 
            ||
| 708 | */  | 
            ||
| 709 | 350 |     public static function lookup(&$context, $vars) { | 
            |
| 722 | |||
| 723 | /**  | 
            ||
| 724 | * Return true when the name is listed in helper table  | 
            ||
| 725 | *  | 
            ||
| 726 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 727 | * @param string $name token name  | 
            ||
| 728 | *  | 
            ||
| 729 | * @return boolean Return true when it is custom helper  | 
            ||
| 730 | */  | 
            ||
| 731 | 467 |     public static function helper(&$context, $name) { | 
            |
| 739 | |||
| 740 | /**  | 
            ||
| 741 | * detect for block custom helper  | 
            ||
| 742 | *  | 
            ||
| 743 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 744 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 745 | *  | 
            ||
| 746 | * @return boolean|null Return true when this token is block custom helper  | 
            ||
| 747 | */  | 
            ||
| 748 | 337 |     protected static function isBlockHelper($context, $vars) { | 
            |
| 759 | |||
| 760 | /**  | 
            ||
| 761 | * validate inline partial  | 
            ||
| 762 | *  | 
            ||
| 763 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 764 | * @param array<boolean|integer|string|array> $vars parsed arguments list  | 
            ||
| 765 | *  | 
            ||
| 766 | * @return boolean Return true always  | 
            ||
| 767 | */  | 
            ||
| 768 | 13 |     protected static function inline(&$context, $vars) { | 
            |
| 780 | |||
| 781 | /**  | 
            ||
| 782 | * validate 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 integer|boolean Return 1 or larger number for runtime partial, return true for other case  | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 788 | */  | 
            ||
| 789 | 95 |     protected static function partial(&$context, $vars) { | 
            |
| 811 | |||
| 812 | /**  | 
            ||
| 813 | * Modify $token when spacing rules matched.  | 
            ||
| 814 | *  | 
            ||
| 815 |      * @param array<string> $token detected handlebars {{ }} token | 
            ||
| 816 | * @param array<string,array|string|integer> $context current compile context  | 
            ||
| 817 | * @param boolean $nost do not do stand alone logic  | 
            ||
| 818 | *  | 
            ||
| 819 | * @return string|null Return compiled code segment for the token  | 
            ||
| 820 | */  | 
            ||
| 821 | 704 |     protected static function spacing(&$token, &$context, $nost = false) { | 
            |
| 872 | }  | 
            ||
| 873 | |||
| 874 | 
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.