Complex classes like Parser 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 Parser, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 24 | class Parser |
||
| 25 | { |
||
| 26 | /** |
||
| 27 | * @var Zone |
||
| 28 | */ |
||
| 29 | private $zone; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * Array of methods that take an ArrayIterator and return an Rdata object. The array key is the Rdata type. |
||
| 33 | * |
||
| 34 | * @var callable[] |
||
| 35 | */ |
||
| 36 | private $rdataHandlers = []; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @var ResourceRecord |
||
| 40 | */ |
||
| 41 | private $currentResourceRecord; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @var string |
||
| 45 | */ |
||
| 46 | private $lastStatedDomain; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var int |
||
| 50 | */ |
||
| 51 | private $lastStatedTtl; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @var string |
||
| 55 | */ |
||
| 56 | private $lastStatedClass; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var string the current ORIGIN value, defaults to the Zone name |
||
| 60 | */ |
||
| 61 | private $origin; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @var int the currently defined default TTL |
||
| 65 | */ |
||
| 66 | private $ttl; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @var ZoneFileFetcherInterface|null Used to get the contents of files included through the directive |
||
| 70 | */ |
||
| 71 | private $fetcher; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @var int |
||
| 75 | */ |
||
| 76 | private $commentOptions; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * @var bool tracks if the class has already been set on a particular line |
||
| 80 | */ |
||
| 81 | 30 | private $classHasBeenSet = false; |
|
| 82 | |||
| 83 | 30 | /** |
|
| 84 | 30 | * @var bool tracks if the TTL has already been set on a particular line |
|
| 85 | 30 | */ |
|
| 86 | private $ttlHasBeenSet = false; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * @var bool tracks if the resource name has already been set on a particular line |
||
| 90 | 27 | */ |
|
| 91 | private $nameHasBeenSet = false; |
||
| 92 | 27 | ||
| 93 | /** |
||
| 94 | * @var bool tracks if the type has already been set on a particular line |
||
| 95 | */ |
||
| 96 | private $typeHasBeenSet = false; |
||
| 97 | |||
| 98 | 30 | /** |
|
| 99 | * Parser constructor. |
||
| 100 | 30 | */ |
|
| 101 | 30 | public function __construct(array $rdataHandlers = [], ?ZoneFileFetcherInterface $fetcher = null) |
|
| 106 | 27 | ||
| 107 | /** |
||
| 108 | * @throws ParseException |
||
| 109 | */ |
||
| 110 | public static function parse(string $name, string $zone, int $commentOptions = Comments::NONE): Zone |
||
| 114 | 30 | ||
| 115 | /** |
||
| 116 | 30 | * @throws ParseException |
|
| 117 | 30 | */ |
|
| 118 | public function makeZone(string $name, string $string, int $commentOptions = Comments::NONE): Zone |
||
| 128 | 30 | ||
| 129 | 30 | /** |
|
| 130 | * @throws ParseException |
||
| 131 | 30 | */ |
|
| 132 | 3 | private function processZone(string $zone): void |
|
| 140 | 15 | ||
| 141 | /** |
||
| 142 | 15 | * @throws ParseException |
|
| 143 | */ |
||
| 144 | private function processLine(string $line): void |
||
| 172 | 29 | ||
| 173 | 29 | /** |
|
| 174 | * @throws ParseException |
||
| 175 | 27 | */ |
|
| 176 | private function processEntry(ResourceRecordIterator $iterator): void |
||
| 215 | |||
| 216 | /** |
||
| 217 | * If no domain-name, TTL, or class is set on the record, populate object with last stated value (RFC-1035). |
||
| 218 | * If $TTL has been set, then that value will fill the resource records TTL (RFC-2308). |
||
| 219 | * |
||
| 220 | * @see https://www.ietf.org/rfc/rfc1035 Section 5.1 |
||
| 221 | * @see https://tools.ietf.org/html/rfc2308 Section 4 |
||
| 222 | */ |
||
| 223 | private function populateNullValues(): void |
||
| 243 | |||
| 244 | /** |
||
| 245 | * Append the $ORIGIN to a subdomain if: |
||
| 246 | * 1) the current $ORIGIN is different, and |
||
| 247 | * 2) the subdomain is not already fully qualified, or |
||
| 248 | 15 | * 3) the subdomain is '@'. |
|
| 249 | * |
||
| 250 | 15 | * @param string $subdomain the subdomain to which the $ORIGIN needs to be appended |
|
| 251 | 13 | * |
|
| 252 | 13 | * @return string The concatenated string of the subdomain.$ORIGIN |
|
| 253 | 13 | */ |
|
| 254 | 13 | private function appendOrigin(string $subdomain): string |
|
| 274 | 7 | ||
| 275 | 5 | /** |
|
| 276 | * Processes control entries at the top of a BIND record, i.e. $ORIGIN, $TTL, $INCLUDE, etc. |
||
| 277 | * |
||
| 278 | 2 | * @throws ParseException |
|
| 279 | */ |
||
| 280 | private function processControlEntry(ResourceRecordIterator $iterator): void |
||
| 300 | 2 | ||
| 301 | 2 | /** |
|
| 302 | 2 | * @throws ParseException |
|
| 303 | 2 | */ |
|
| 304 | private function includeFile(ResourceRecordIterator $iterator): void |
||
| 336 | 30 | ||
| 337 | /** |
||
| 338 | 30 | * @param string $string the string proceeding the $INCLUDE directive |
|
| 339 | * |
||
| 340 | * @return array an array containing [$path, $domain] |
||
| 341 | */ |
||
| 342 | 30 | private function extractIncludeArguments(string $string): array |
|
| 361 | |||
| 362 | /** |
||
| 363 | 30 | * Determine if iterant is a resource name. |
|
| 364 | */ |
||
| 365 | 30 | private function isResourceName(ResourceRecordIterator $iterator): bool |
|
| 393 | 30 | ||
| 394 | /** |
||
| 395 | * Determine if iterant is a class. |
||
| 396 | * |
||
| 397 | * @param string|null $origin the previously assumed resource record parameter, either 'TTL' or NULL |
||
| 398 | */ |
||
| 399 | private function isClass(ResourceRecordIterator $iterator, $origin = null): bool |
||
| 419 | 27 | ||
| 420 | /** |
||
| 421 | * Determine if current iterant is an Rdata type string. |
||
| 422 | */ |
||
| 423 | private function isType(ResourceRecordIterator $iterator): bool |
||
| 431 | 30 | ||
| 432 | /** |
||
| 433 | 30 | * Determine if iterant is a control entry such as $TTL, $ORIGIN, $INCLUDE, etcetera. |
|
| 434 | */ |
||
| 435 | 30 | private function isControlEntry(ResourceRecordIterator $iterator): bool |
|
| 439 | 5 | ||
| 440 | /** |
||
| 441 | 5 | * Determine if the iterant is a TTL (i.e. it is an integer after domain-name). |
|
| 442 | * |
||
| 443 | * @param string $origin the previously assumed resource record parameter, either 'CLASS' or NULL |
||
| 444 | 30 | */ |
|
| 445 | 30 | private function isTTL(ResourceRecordIterator $iterator, $origin = null): bool |
|
| 469 | 15 | ||
| 470 | 15 | /** |
|
| 471 | * Split a DNS zone line into a resource record and a comment. |
||
| 472 | * |
||
| 473 | 15 | * @return array [$entry, $comment] |
|
| 474 | */ |
||
| 475 | private function extractComment(string $rr): array |
||
| 498 | |||
| 499 | /** |
||
| 500 | * Extract text within double quotation context. |
||
| 501 | */ |
||
| 502 | private function extractDoubleQuotedText(StringIterator $string): string |
||
| 523 | |||
| 524 | /** |
||
| 525 | * @throws ParseException |
||
| 526 | */ |
||
| 527 | private function extractRdata(ResourceRecordIterator $iterator): RdataInterface |
||
| 542 | } |
||
| 543 |