Complex classes like CLImate 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 CLImate, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
84 | class CLImate |
||
85 | { |
||
86 | /** |
||
87 | * An instance of the Style class |
||
88 | * |
||
89 | * @var \League\CLImate\Decorator\Style $style |
||
90 | */ |
||
91 | public $style; |
||
92 | |||
93 | /** |
||
94 | * An instance of the Terminal Object Router class |
||
95 | * |
||
96 | * @var \League\CLImate\TerminalObject\Router\Router $router |
||
97 | */ |
||
98 | protected $router; |
||
99 | |||
100 | /** |
||
101 | * An instance of the Settings Manager class |
||
102 | * |
||
103 | * @var \League\CLImate\Settings\Manager $settings |
||
104 | */ |
||
105 | protected $settings; |
||
106 | |||
107 | /** |
||
108 | * An instance of the Argument Manager class |
||
109 | * |
||
110 | * @var \League\CLImate\Argument\Manager $arguments |
||
111 | */ |
||
112 | public $arguments; |
||
113 | |||
114 | /** |
||
115 | * An instance of the Output class |
||
116 | * |
||
117 | * @var \League\CLImate\Util\Output $output |
||
118 | */ |
||
119 | public $output; |
||
120 | |||
121 | /** |
||
122 | * An instance of the Util Factory |
||
123 | * |
||
124 | * @var \League\CLImate\Util\UtilFactory $util |
||
125 | */ |
||
126 | protected $util; |
||
127 | |||
128 | 936 | public function __construct() |
|
129 | { |
||
130 | 936 | $this->setStyle(new Style()); |
|
131 | 936 | $this->setRouter(new Router()); |
|
132 | 936 | $this->setSettingsManager(new SettingsManager()); |
|
133 | 936 | $this->setOutput(new Output()); |
|
134 | 936 | $this->setUtil(new UtilFactory()); |
|
135 | 936 | $this->setArgumentManager(new ArgumentManager()); |
|
136 | 936 | } |
|
137 | |||
138 | /** |
||
139 | * Set the style property |
||
140 | * |
||
141 | * @param \League\CLImate\Decorator\Style $style |
||
142 | */ |
||
143 | 936 | public function setStyle(Style $style) |
|
144 | { |
||
145 | 936 | $this->style = $style; |
|
146 | 936 | } |
|
147 | |||
148 | /** |
||
149 | * Set the router property |
||
150 | * |
||
151 | * @param \League\CLImate\TerminalObject\Router\Router $router |
||
152 | */ |
||
153 | 936 | public function setRouter(Router $router) |
|
154 | { |
||
155 | 936 | $this->router = $router; |
|
156 | 936 | } |
|
157 | |||
158 | /** |
||
159 | * Set the settings property |
||
160 | * |
||
161 | * @param \League\CLImate\Settings\Manager $manager |
||
162 | */ |
||
163 | 936 | public function setSettingsManager(SettingsManager $manager) |
|
164 | { |
||
165 | 936 | $this->settings = $manager; |
|
166 | 936 | } |
|
167 | |||
168 | /** |
||
169 | * Set the arguments property |
||
170 | * |
||
171 | * @param \League\CLImate\Argument\Manager $manager |
||
172 | */ |
||
173 | 936 | public function setArgumentManager(ArgumentManager $manager) |
|
174 | { |
||
175 | 936 | $this->arguments = $manager; |
|
176 | 936 | } |
|
177 | |||
178 | /** |
||
179 | * Set the output property |
||
180 | * |
||
181 | * @param \League\CLImate\Util\Output $output |
||
182 | */ |
||
183 | 936 | public function setOutput(Output $output) |
|
184 | { |
||
185 | 936 | $this->output = $output; |
|
186 | 936 | } |
|
187 | |||
188 | /** |
||
189 | * Set the util property |
||
190 | * |
||
191 | * @param \League\CLImate\Util\UtilFactory $util |
||
192 | */ |
||
193 | 936 | public function setUtil(UtilFactory $util) |
|
194 | { |
||
195 | 936 | $this->util = $util; |
|
196 | 936 | } |
|
197 | |||
198 | /** |
||
199 | * Extend CLImate with custom methods |
||
200 | * |
||
201 | * @param string|object|array $class |
||
202 | * @param string $key Optional custom key instead of class name |
||
203 | * |
||
204 | * @return \League\CLImate\CLImate |
||
205 | */ |
||
206 | 36 | public function extend($class, $key = null) |
|
207 | { |
||
208 | 36 | $this->router->addExtension($key, $class); |
|
|
|||
209 | |||
210 | 28 | return $this; |
|
211 | } |
||
212 | |||
213 | /** |
||
214 | * Force ansi support on |
||
215 | * |
||
216 | * @return \League\CLImate\CLImate |
||
217 | */ |
||
218 | 4 | public function forceAnsiOn() |
|
224 | |||
225 | /** |
||
226 | * Force ansi support off |
||
227 | * |
||
228 | * @return \League\CLImate\CLImate |
||
229 | */ |
||
230 | 4 | public function forceAnsiOff() |
|
236 | |||
237 | /** |
||
238 | * Write line to writer once |
||
239 | * |
||
240 | * @param string|array $writer |
||
241 | * |
||
242 | * @return \League\CLImate\CLImate |
||
243 | */ |
||
244 | 4 | public function to($writer) |
|
250 | |||
251 | /** |
||
252 | * Output the program's usage statement |
||
253 | * |
||
254 | * @param array $argv |
||
255 | */ |
||
256 | 4 | public function usage(array $argv = null) |
|
260 | |||
261 | /** |
||
262 | * Set the program's description |
||
263 | * |
||
264 | * @param string $description |
||
265 | * |
||
266 | * @return \League\CLImate\CLImate |
||
267 | */ |
||
268 | 4 | public function description($description) |
|
274 | |||
275 | /** |
||
276 | * they pass in a total, set the total |
||
277 | * |
||
278 | * @param iterable $data Array or any other iterable object |
||
279 | * @param callable $callback |
||
280 | */ |
||
281 | public function each($data, callable $callback = null) |
||
302 | |||
303 | /** |
||
304 | * Check if we have valid output |
||
305 | * |
||
306 | * @param mixed $output |
||
307 | * |
||
308 | * @return boolean |
||
309 | */ |
||
310 | 76 | protected function hasOutput($output) |
|
319 | |||
320 | /** |
||
321 | * Search for the method within the string |
||
322 | * and route it if we find one. |
||
323 | * |
||
324 | * @param string $method |
||
325 | * @param string $name |
||
326 | * |
||
327 | * @return string The new string without the executed method. |
||
328 | */ |
||
329 | 556 | protected function parseStyleMethod($method, $name) |
|
344 | |||
345 | /** |
||
346 | * Search for any style methods within the name and apply them |
||
347 | * |
||
348 | * @param string $name |
||
349 | * @param array $method_search |
||
350 | * |
||
351 | * @return string Anything left over after applying styles |
||
352 | */ |
||
353 | 556 | protected function applyStyleMethods($name, $method_search = null) |
|
368 | |||
369 | /** |
||
370 | * Search for style methods in the current name |
||
371 | * |
||
372 | * @param string $name |
||
373 | * @param array $search |
||
374 | * @return string |
||
375 | */ |
||
376 | 556 | protected function searchForStyleMethods($name, $search) |
|
386 | |||
387 | /** |
||
388 | * Build up the terminal object and return it |
||
389 | * |
||
390 | * @param string $name |
||
391 | * @param array $arguments |
||
392 | * |
||
393 | * @return object|null |
||
394 | */ |
||
395 | 556 | protected function buildTerminalObject($name, $arguments) |
|
411 | |||
412 | /** |
||
413 | * Route anything leftover after styles were applied |
||
414 | * |
||
415 | * @param string $name |
||
416 | * @param array $arguments |
||
417 | * |
||
418 | * @return object|null |
||
419 | */ |
||
420 | 556 | protected function routeRemainingMethod($name, array $arguments) |
|
438 | |||
439 | /** |
||
440 | * Magic method for anything called that doesn't exist |
||
441 | * |
||
442 | * @param string $requested_method |
||
443 | * @param array $arguments |
||
444 | * |
||
445 | * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject |
||
446 | * |
||
447 | * List of many of the possible method being called here |
||
448 | * documented at the top of this class. |
||
449 | */ |
||
450 | 556 | public function __call($requested_method, $arguments) |
|
470 | } |
||
471 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.