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 |