Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CLI 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 CLI, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class CLI { |
||
32 | |||
33 | public static $readline_support = false; |
||
34 | |||
35 | public static $wait_msg = 'Press any key to continue...'; |
||
36 | |||
37 | public static $segments = []; |
||
38 | |||
39 | protected static $options = []; |
||
40 | |||
41 | protected static $initialized = false; |
||
42 | |||
43 | // Used by progress bar |
||
44 | protected static $inProgress = false; |
||
45 | |||
46 | protected static $foreground_colors = array( |
||
47 | 'black' => '0;30', |
||
48 | 'dark_gray' => '1;30', |
||
49 | 'blue' => '0;34', |
||
50 | 'dark_blue' => '1;34', |
||
51 | 'light_blue' => '1;34', |
||
52 | 'green' => '0;32', |
||
53 | 'light_green' => '1;32', |
||
54 | 'cyan' => '0;36', |
||
55 | 'light_cyan' => '1;36', |
||
56 | 'red' => '0;31', |
||
57 | 'light_red' => '1;31', |
||
58 | 'purple' => '0;35', |
||
59 | 'light_purple' => '1;35', |
||
60 | 'light_yellow' => '0;33', |
||
61 | 'yellow' => '1;33', |
||
62 | 'light_gray' => '0;37', |
||
63 | 'white' => '1;37', |
||
64 | ); |
||
65 | |||
66 | protected static $background_colors = array( |
||
67 | 'black' => '40', |
||
68 | 'red' => '41', |
||
69 | 'green' => '42', |
||
70 | 'yellow' => '43', |
||
71 | 'blue' => '44', |
||
72 | 'magenta' => '45', |
||
73 | 'cyan' => '46', |
||
74 | 'light_gray' => '47', |
||
75 | ); |
||
76 | |||
77 | //-------------------------------------------------------------------- |
||
78 | |||
79 | /** |
||
80 | * Static constructor. Parses all the CLI params. |
||
81 | */ |
||
82 | public static function _init() |
||
102 | |||
103 | //-------------------------------------------------------------------- |
||
104 | |||
105 | /** |
||
106 | * Grabs an individual |
||
107 | * |
||
108 | * @param $index |
||
109 | * @return null |
||
110 | */ |
||
111 | public static function segment($index) |
||
120 | |||
121 | //-------------------------------------------------------------------- |
||
122 | |||
123 | /** |
||
124 | * Returns the command string portion of the arguments. Used |
||
125 | * by the 'sprint' CLI script to grab the portion of the arguments |
||
126 | * that is used to call the CodeIgniter application. |
||
127 | * |
||
128 | * @return string |
||
129 | */ |
||
130 | public static function cli_string() |
||
134 | |||
135 | //-------------------------------------------------------------------- |
||
136 | |||
137 | |||
138 | |||
139 | /** |
||
140 | * Get input from the shell, using readline or the standard STDIN |
||
141 | * |
||
142 | * Named options must be in the following formats: |
||
143 | * php index.php user -v --v -name=John --name=John |
||
144 | * |
||
145 | * @param string|int $name the name of the option (int if unnamed) |
||
146 | * @return string |
||
147 | */ |
||
148 | public static function input($prefix = '') |
||
158 | |||
159 | //-------------------------------------------------------------------- |
||
160 | |||
161 | /** |
||
162 | * Asks the user for input. This can have either 1 or 2 arguments. |
||
163 | * |
||
164 | * Usage: |
||
165 | * |
||
166 | * // Waits for any key press |
||
167 | * CLI::prompt(); |
||
168 | * |
||
169 | * // Takes any input |
||
170 | * $color = CLI::prompt('What is your favorite color?'); |
||
171 | * |
||
172 | * // Takes any input, but offers default |
||
173 | * $color = CLI::prompt('What is your favourite color?', 'white'); |
||
174 | * |
||
175 | * // Will only accept the options in the array |
||
176 | * $ready = CLI::prompt('Are you ready?', array('y','n')); |
||
177 | * |
||
178 | * @return string the user input |
||
179 | */ |
||
180 | public static function prompt() |
||
276 | |||
277 | //-------------------------------------------------------------------- |
||
278 | |||
279 | /** |
||
280 | * Outputs a string to the cli. If you send an array it will implode them |
||
281 | * with a line break. |
||
282 | * |
||
283 | * @param string|array $text the text to output, or array of lines |
||
284 | */ |
||
285 | View Code Duplication | public static function write($text = '', $foreground = null, $background = null) |
|
299 | |||
300 | //-------------------------------------------------------------------- |
||
301 | |||
302 | /** |
||
303 | * Outputs an error to the CLI using STDERR instead of STDOUT |
||
304 | * |
||
305 | * @param string|array $text the text to output, or array of errors |
||
306 | */ |
||
307 | View Code Duplication | public static function error($text = '', $foreground = 'light_red', $background = null) |
|
321 | |||
322 | //-------------------------------------------------------------------- |
||
323 | |||
324 | /** |
||
325 | * Beeps a certain number of times. |
||
326 | * |
||
327 | * @param int $num the number of times to beep |
||
328 | */ |
||
329 | public static function beep($num = 1) |
||
333 | |||
334 | //-------------------------------------------------------------------- |
||
335 | |||
336 | /** |
||
337 | * Waits a certain number of seconds, optionally showing a wait message and |
||
338 | * waiting for a key press. |
||
339 | * |
||
340 | * @param int $seconds number of seconds |
||
341 | * @param bool $countdown show a countdown or not |
||
342 | */ |
||
343 | public static function wait($seconds = 0, $countdown = false) |
||
371 | |||
372 | |||
373 | //-------------------------------------------------------------------- |
||
374 | |||
375 | /** |
||
376 | * if operating system === windows |
||
377 | */ |
||
378 | public static function is_windows() |
||
382 | |||
383 | //-------------------------------------------------------------------- |
||
384 | |||
385 | /** |
||
386 | * Enter a number of empty lines |
||
387 | * |
||
388 | * @param integer Number of lines to output |
||
389 | * @return void |
||
390 | */ |
||
391 | public static function new_line($num = 1) |
||
399 | |||
400 | //-------------------------------------------------------------------- |
||
401 | |||
402 | /** |
||
403 | * Clears the screen of output |
||
404 | * |
||
405 | * @return void |
||
406 | */ |
||
407 | public static function clear_screen() |
||
417 | |||
418 | //-------------------------------------------------------------------- |
||
419 | |||
420 | /** |
||
421 | * Returns the given text with the correct color codes for a foreground and |
||
422 | * optionally a background color. |
||
423 | * |
||
424 | * @param string $text the text to color |
||
425 | * @param string $foreground the foreground color |
||
426 | * @param string $background the background color |
||
427 | * @param string $format other formatting to apply. Currently only 'underline' is understood |
||
428 | * @return string the color coded string |
||
429 | */ |
||
430 | public static function color($text, $foreground, $background = null, $format=null) |
||
463 | |||
464 | //-------------------------------------------------------------------- |
||
465 | |||
466 | public static function getWidth($default=80) |
||
475 | |||
476 | //-------------------------------------------------------------------- |
||
477 | |||
478 | public static function getHeight($default=32) |
||
487 | |||
488 | //-------------------------------------------------------------------- |
||
489 | |||
490 | /** |
||
491 | * Displays a progress bar on the CLI. You must call it repeatedly |
||
492 | * to update it. Set $thisStep = false to erase the progress bar. |
||
493 | * |
||
494 | * @param int $thisStep |
||
495 | * @param int $totalSteps |
||
496 | */ |
||
497 | public static function showProgress($thisStep=1, $totalSteps=10) |
||
531 | |||
532 | //-------------------------------------------------------------------- |
||
533 | |||
534 | /** |
||
535 | * Checks to see if an option was passed to us on the CLI and returns |
||
536 | * the value if so. Otherwise, returns null. |
||
537 | * |
||
538 | * @param $name |
||
539 | * |
||
540 | * @return null |
||
541 | */ |
||
542 | public static function option($name) |
||
552 | |||
553 | //-------------------------------------------------------------------- |
||
554 | |||
555 | /** |
||
556 | * Gets all of the options set and returns that array. |
||
557 | * |
||
558 | * @return array |
||
559 | */ |
||
560 | public static function getOptions() |
||
564 | |||
565 | //-------------------------------------------------------------------- |
||
566 | |||
567 | /** |
||
568 | * Returns the options as a string, suitable for passing along on |
||
569 | * the CLI to other commands. |
||
570 | */ |
||
571 | public static function optionString() |
||
593 | |||
594 | //-------------------------------------------------------------------- |
||
595 | |||
596 | |||
597 | |||
598 | /** |
||
599 | * Takes a string and writes it to the command line, wrapping to a maximum |
||
600 | * width. If no maximum width is specified, will wrap to the window's max |
||
601 | * width. |
||
602 | * |
||
603 | * If an int is passed into $pad_left, then all strings after the first |
||
604 | * will padded with that many spaces to the left. Useful when printing |
||
605 | * short descriptions that need to start on an existing line. |
||
606 | * |
||
607 | * @param null $string |
||
608 | * @param int $max |
||
609 | * @param int $pad_left |
||
610 | */ |
||
611 | public static function wrap($string=null, $max=0, $pad_left=0) |
||
652 | |||
653 | //-------------------------------------------------------------------- |
||
654 | |||
655 | /** |
||
656 | * Parses the command line it was called from and collects all |
||
657 | * options and valid segments. |
||
658 | * |
||
659 | * I tried to use getopt but had it fail occasionally to find any |
||
660 | * but argc has always had our back. We don't have all of the "power" |
||
661 | * of getopt but this does us just fine. |
||
662 | */ |
||
663 | protected static function parseCommand() |
||
697 | |||
698 | //-------------------------------------------------------------------- |
||
699 | |||
700 | } |
||
701 | |||
703 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.