Complex classes like CommandLineOptions 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 CommandLineOptions, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
30 | class CommandLineOptions |
||
31 | { |
||
32 | /** |
||
33 | * Error code for invalid input |
||
34 | */ |
||
35 | const INPUT_ERROR = 23; |
||
36 | |||
37 | /** |
||
38 | * The minimum rule priority. |
||
39 | * |
||
40 | * @var integer |
||
41 | */ |
||
42 | protected $minimumPriority = Rule::LOWEST_PRIORITY; |
||
43 | |||
44 | /** |
||
45 | * The maximum rule priority. |
||
46 | * |
||
47 | * @var integer |
||
48 | */ |
||
49 | protected $maximumPriority = Rule::HIGHEST_PRIORITY; |
||
50 | |||
51 | /** |
||
52 | * A php source code filename or directory. |
||
53 | * |
||
54 | * @var string |
||
55 | */ |
||
56 | protected $inputPath; |
||
57 | |||
58 | /** |
||
59 | * The specified report format. |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | protected $reportFormat; |
||
64 | |||
65 | /** |
||
66 | * An optional filename for the generated report. |
||
67 | * |
||
68 | * @var string |
||
69 | */ |
||
70 | protected $reportFile; |
||
71 | |||
72 | /** |
||
73 | * Additional report files. |
||
74 | * |
||
75 | * @var array |
||
76 | */ |
||
77 | protected $reportFiles = array(); |
||
78 | |||
79 | /** |
||
80 | * A ruleset filename or a comma-separated string of ruleset filenames. |
||
81 | * |
||
82 | * @var string |
||
83 | */ |
||
84 | protected $ruleSets; |
||
85 | |||
86 | /** |
||
87 | * File name of a PHPUnit code coverage report. |
||
88 | * |
||
89 | * @var string |
||
90 | */ |
||
91 | protected $coverageReport; |
||
92 | |||
93 | /** |
||
94 | * A string of comma-separated extensions for valid php source code filenames. |
||
95 | * |
||
96 | * @var string |
||
97 | */ |
||
98 | protected $extensions; |
||
99 | |||
100 | /** |
||
101 | * A string of comma-separated pattern that is used to exclude directories. |
||
102 | * |
||
103 | * @var string |
||
104 | */ |
||
105 | protected $ignore; |
||
106 | |||
107 | /** |
||
108 | * Should the shell show the current phpmd version? |
||
109 | * |
||
110 | * @var boolean |
||
111 | */ |
||
112 | protected $version = false; |
||
113 | |||
114 | /** |
||
115 | * Should PHPMD run in strict mode? |
||
116 | * |
||
117 | * @var boolean |
||
118 | * @since 1.2.0 |
||
119 | */ |
||
120 | protected $strict = false; |
||
121 | |||
122 | /** |
||
123 | * Should PHPMD exit without error code even if violation is found? |
||
124 | * |
||
125 | * @var boolean |
||
126 | */ |
||
127 | protected $ignoreViolationsOnExit = false; |
||
128 | |||
129 | /** |
||
130 | * List of available rule-sets. |
||
131 | * |
||
132 | * @var array(string) |
||
133 | */ |
||
134 | protected $availableRuleSets = array(); |
||
135 | |||
136 | /** |
||
137 | * Constructs a new command line options instance. |
||
138 | * |
||
139 | * @param array $args |
||
140 | * @param array $availableRuleSets |
||
141 | * @throws \InvalidArgumentException |
||
142 | */ |
||
143 | 40 | public function __construct(array $args, array $availableRuleSets = array()) |
|
144 | { |
||
145 | // Remove current file name |
||
146 | 40 | array_shift($args); |
|
147 | |||
148 | 40 | $this->availableRuleSets = $availableRuleSets; |
|
149 | |||
150 | 40 | $arguments = array(); |
|
151 | 40 | while (($arg = array_shift($args)) !== null) { |
|
152 | 40 | switch ($arg) { |
|
153 | case '--min-priority': |
||
154 | case '--minimum-priority': |
||
155 | case '--minimumpriority': |
||
156 | 1 | $this->minimumPriority = (int)array_shift($args); |
|
157 | 1 | break; |
|
158 | case '--max-priority': |
||
159 | case '--maximum-priority': |
||
160 | case '--maximumpriority': |
||
161 | 1 | $this->maximumPriority = (int)array_shift($args); |
|
162 | 1 | break; |
|
163 | case '--report-file': |
||
164 | case '--reportfile': |
||
165 | 4 | $this->reportFile = array_shift($args); |
|
166 | 4 | break; |
|
167 | case '--input-file': |
||
168 | case '--inputfile': |
||
169 | 6 | array_unshift($arguments, $this->readInputFile(array_shift($args))); |
|
170 | 5 | break; |
|
171 | case '--coverage': |
||
172 | 1 | $this->coverageReport = array_shift($args); |
|
173 | 1 | break; |
|
174 | case '--extensions': |
||
175 | 1 | $this->logDeprecated('extensions', 'suffixes'); |
|
176 | /* Deprecated: We use the suffixes option now */ |
||
177 | 1 | $this->extensions = array_shift($args); |
|
178 | 1 | break; |
|
179 | case '--suffixes': |
||
180 | $this->extensions = array_shift($args); |
||
181 | break; |
||
182 | case '--ignore': |
||
183 | 1 | $this->logDeprecated('ignore', 'exclude'); |
|
184 | /* Deprecated: We use the exclude option now */ |
||
185 | 1 | $this->ignore = array_shift($args); |
|
186 | 1 | break; |
|
187 | case '--exclude': |
||
188 | $this->ignore = array_shift($args); |
||
189 | break; |
||
190 | case '--version': |
||
191 | 1 | $this->version = true; |
|
192 | |||
193 | 1 | return; |
|
194 | case '--strict': |
||
195 | 1 | $this->strict = true; |
|
196 | 1 | break; |
|
197 | case '--not-strict': |
||
198 | $this->strict = false; |
||
199 | break; |
||
200 | case '--ignore-violations-on-exit': |
||
201 | 1 | $this->ignoreViolationsOnExit = true; |
|
202 | 1 | break; |
|
203 | case '--reportfile-html': |
||
204 | case '--reportfile-text': |
||
205 | case '--reportfile-xml': |
||
206 | case '--reportfile-json': |
||
207 | 4 | preg_match('(^\-\-reportfile\-(xml|html|text|json)$)', $arg, $match); |
|
208 | 4 | $this->reportFiles[$match[1]] = array_shift($args); |
|
209 | 4 | break; |
|
210 | default: |
||
211 | 39 | $arguments[] = $arg; |
|
212 | 39 | break; |
|
213 | } |
||
214 | } |
||
215 | |||
216 | 38 | if (count($arguments) < 3) { |
|
217 | 1 | throw new \InvalidArgumentException($this->usage(), self::INPUT_ERROR); |
|
218 | } |
||
219 | |||
220 | 37 | $this->inputPath = (string)array_shift($arguments); |
|
221 | 37 | $this->reportFormat = (string)array_shift($arguments); |
|
222 | 37 | $this->ruleSets = (string)array_shift($arguments); |
|
223 | 37 | } |
|
224 | |||
225 | /** |
||
226 | * Returns a php source code filename or directory. |
||
227 | * |
||
228 | * @return string |
||
229 | */ |
||
230 | 6 | public function getInputPath() |
|
231 | { |
||
232 | 6 | return $this->inputPath; |
|
233 | } |
||
234 | |||
235 | /** |
||
236 | * Returns the specified report format. |
||
237 | * |
||
238 | * @return string |
||
239 | */ |
||
240 | 2 | public function getReportFormat() |
|
241 | { |
||
242 | 2 | return $this->reportFormat; |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Returns the output filename for a generated report or <b>null</b> when |
||
247 | * the report should be displayed in STDOUT. |
||
248 | * |
||
249 | * @return string |
||
250 | */ |
||
251 | 4 | public function getReportFile() |
|
252 | { |
||
253 | 4 | return $this->reportFile; |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * Returns a hash with report files specified for different renderers. The |
||
258 | * key represents the report format and the value the report file location. |
||
259 | * |
||
260 | * @return array |
||
261 | */ |
||
262 | 8 | public function getReportFiles() |
|
263 | { |
||
264 | 8 | return $this->reportFiles; |
|
265 | } |
||
266 | |||
267 | /** |
||
268 | * Returns a ruleset filename or a comma-separated string of ruleset |
||
269 | * |
||
270 | * @return string |
||
271 | */ |
||
272 | 6 | public function getRuleSets() |
|
273 | { |
||
274 | 6 | return $this->ruleSets; |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * Returns the minimum rule priority. |
||
279 | * |
||
280 | * @return integer |
||
281 | */ |
||
282 | 6 | public function getMinimumPriority() |
|
283 | { |
||
284 | 6 | return $this->minimumPriority; |
|
285 | } |
||
286 | |||
287 | /** |
||
288 | * Returns the maximum rule priority. |
||
289 | * |
||
290 | * @return integer |
||
291 | */ |
||
292 | 5 | public function getMaximumPriority() |
|
293 | { |
||
294 | 5 | return $this->maximumPriority; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * Returns the file name of a supplied code coverage report or <b>NULL</b> |
||
299 | * if the user has not supplied the --coverage option. |
||
300 | * |
||
301 | * @return string |
||
302 | */ |
||
303 | 6 | public function getCoverageReport() |
|
304 | { |
||
305 | 6 | return $this->coverageReport; |
|
306 | } |
||
307 | |||
308 | /** |
||
309 | * Returns a string of comma-separated extensions for valid php source code |
||
310 | * filenames or <b>null</b> when this argument was not set. |
||
311 | * |
||
312 | * @return string |
||
313 | */ |
||
314 | 4 | public function getExtensions() |
|
315 | { |
||
316 | 4 | return $this->extensions; |
|
317 | } |
||
318 | |||
319 | /** |
||
320 | * Returns string of comma-separated pattern that is used to exclude |
||
321 | * directories or <b>null</b> when this argument was not set. |
||
322 | * |
||
323 | * @return string |
||
324 | */ |
||
325 | 4 | public function getIgnore() |
|
326 | { |
||
327 | 4 | return $this->ignore; |
|
328 | } |
||
329 | |||
330 | /** |
||
331 | * Was the <b>--version</b> passed to PHPMD's command line interface? |
||
332 | * |
||
333 | * @return boolean |
||
334 | */ |
||
335 | 6 | public function hasVersion() |
|
336 | { |
||
337 | 6 | return $this->version; |
|
338 | } |
||
339 | |||
340 | /** |
||
341 | * Was the <b>--strict</b> option passed to PHPMD's command line interface? |
||
342 | * |
||
343 | * @return boolean |
||
344 | * @since 1.2.0 |
||
345 | */ |
||
346 | 6 | public function hasStrict() |
|
347 | { |
||
348 | 6 | return $this->strict; |
|
349 | } |
||
350 | |||
351 | /** |
||
352 | * Was the <b>--ignore-violations-on-exit</b> passed to PHPMD's command line interface? |
||
353 | * |
||
354 | * @return boolean |
||
355 | */ |
||
356 | 6 | public function ignoreViolationsOnExit() |
|
357 | { |
||
358 | 6 | return $this->ignoreViolationsOnExit; |
|
359 | } |
||
360 | |||
361 | /** |
||
362 | * Creates a report renderer instance based on the user's command line |
||
363 | * argument. |
||
364 | * |
||
365 | * Valid renderers are: |
||
366 | * <ul> |
||
367 | * <li>xml</li> |
||
368 | * <li>html</li> |
||
369 | * <li>text</li> |
||
370 | * <li>json</li> |
||
371 | * </ul> |
||
372 | * |
||
373 | * @param string $reportFormat |
||
374 | * @return \PHPMD\AbstractRenderer |
||
375 | * @throws \InvalidArgumentException When the specified renderer does not exist. |
||
376 | */ |
||
377 | 12 | public function createRenderer($reportFormat = null) |
|
378 | { |
||
379 | 12 | $reportFormat = $reportFormat ?: $this->reportFormat; |
|
380 | |||
381 | 12 | switch ($reportFormat) { |
|
382 | case 'xml': |
||
383 | 1 | return $this->createXmlRenderer(); |
|
384 | case 'html': |
||
385 | 1 | return $this->createHtmlRenderer(); |
|
386 | case 'text': |
||
387 | 5 | return $this->createTextRenderer(); |
|
388 | case 'json': |
||
389 | return $this->createJsonRenderer(); |
||
390 | default: |
||
391 | 5 | return $this->createCustomRenderer(); |
|
392 | } |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * @return \PHPMD\Renderer\XMLRenderer |
||
397 | */ |
||
398 | 1 | protected function createXmlRenderer() |
|
399 | { |
||
400 | 1 | return new XMLRenderer(); |
|
401 | } |
||
402 | |||
403 | /** |
||
404 | * @return \PHPMD\Renderer\TextRenderer |
||
405 | */ |
||
406 | 5 | protected function createTextRenderer() |
|
407 | { |
||
408 | 5 | return new TextRenderer(); |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * @return \PHPMD\Renderer\HTMLRenderer |
||
413 | */ |
||
414 | 1 | protected function createHtmlRenderer() |
|
415 | { |
||
416 | 1 | return new HTMLRenderer(); |
|
417 | } |
||
418 | |||
419 | /** |
||
420 | * @return \PHPMD\Renderer\JSONRenderer |
||
421 | */ |
||
422 | protected function createJsonRenderer() |
||
423 | { |
||
424 | return new JSONRenderer(); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * @return \PHPMD\AbstractRenderer |
||
429 | * @throws \InvalidArgumentException |
||
430 | */ |
||
431 | 5 | protected function createCustomRenderer() |
|
463 | |||
464 | /** |
||
465 | * Returns usage information for the PHPMD command line interface. |
||
466 | * |
||
467 | * @return string |
||
468 | */ |
||
469 | 4 | public function usage() |
|
470 | { |
||
471 | 4 | $availableRenderers = $this->getListOfAvailableRenderers(); |
|
472 | |||
473 | return 'Mandatory arguments:' . \PHP_EOL . |
||
474 | '1) A php source code filename or directory. Can be a comma-' . |
||
475 | 'separated string' . \PHP_EOL . |
||
476 | '2) A report format' . \PHP_EOL . |
||
477 | '3) A ruleset filename or a comma-separated string of ruleset' . |
||
478 | 'filenames' . \PHP_EOL . \PHP_EOL . |
||
479 | 4 | 'Available formats: ' . $availableRenderers . '.' . \PHP_EOL . |
|
480 | 4 | 'Available rulesets: ' . implode(', ', $this->availableRuleSets) . '.' . \PHP_EOL . \PHP_EOL . |
|
496 | |||
497 | /** |
||
498 | * Get a list of available renderers |
||
499 | * |
||
500 | * @return string The list of renderers found. |
||
501 | */ |
||
502 | 4 | protected function getListOfAvailableRenderers() |
|
521 | |||
522 | /** |
||
523 | * Logs a deprecated option to the current user interface. |
||
524 | * |
||
525 | * @param string $deprecatedName |
||
526 | * @param string $newName |
||
527 | * @return void |
||
528 | */ |
||
529 | 2 | protected function logDeprecated($deprecatedName, $newName) |
|
530 | { |
||
531 | 2 | $message = sprintf( |
|
532 | 2 | 'The --%s option is deprecated, please use --%s instead.', |
|
533 | 2 | $deprecatedName, |
|
534 | 2 | $newName |
|
535 | ); |
||
536 | |||
537 | 2 | fwrite(STDERR, $message . PHP_EOL . PHP_EOL); |
|
538 | 2 | } |
|
539 | |||
540 | /** |
||
541 | * This method takes the given input file, reads the newline separated paths |
||
542 | * from that file and creates a comma separated string of the file paths. If |
||
543 | * the given <b>$inputFile</b> not exists, this method will throw an |
||
544 | * exception. |
||
545 | * |
||
546 | * @param string $inputFile Specified input file name. |
||
547 | * @return string |
||
548 | * @throws \InvalidArgumentException If the specified input file does not exist. |
||
549 | * @since 1.1.0 |
||
550 | */ |
||
551 | 6 | protected function readInputFile($inputFile) |
|
558 | } |
||
559 |
If you suppress an error, we recommend checking for the error condition explicitly: