Complex classes like GameQ 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 GameQ, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
41 | class GameQ |
||
42 | { |
||
43 | /* |
||
44 | * Constants |
||
45 | */ |
||
46 | |||
47 | /* Static Section */ |
||
48 | |||
49 | /** |
||
50 | * Holds the instance of itself |
||
51 | * |
||
52 | * @type self |
||
53 | */ |
||
54 | protected static $instance = null; |
||
55 | |||
56 | /** |
||
57 | * Create a new instance of this class |
||
58 | * |
||
59 | * @return \GameQ\GameQ |
||
60 | */ |
||
61 | 1 | public static function factory() |
|
70 | |||
71 | /* Dynamic Section */ |
||
72 | |||
73 | /** |
||
74 | * Default options |
||
75 | * |
||
76 | * @type array |
||
77 | */ |
||
78 | protected $options = [ |
||
79 | 'debug' => false, |
||
80 | 'timeout' => 3, // Seconds |
||
81 | 'filters' => [ |
||
82 | // Default normalize |
||
83 | 'normalize_d751713988987e9331980363e24189ce' => [ |
||
84 | 'filter' => 'normalize', |
||
85 | 'options' => [], |
||
86 | ], |
||
87 | ], |
||
88 | // Advanced settings |
||
89 | 'stream_timeout' => 200000, // See http://www.php.net/manual/en/function.stream-select.php for more info |
||
90 | 'write_wait' => 500, |
||
91 | // How long (in micro-seconds) to pause between writing to server sockets, helps cpu usage |
||
92 | |||
93 | // Used for generating protocol test data |
||
94 | 'capture_packets_file' => null, |
||
95 | ]; |
||
96 | |||
97 | /** |
||
98 | * Array of servers being queried |
||
99 | * |
||
100 | * @type array |
||
101 | */ |
||
102 | protected $servers = []; |
||
103 | |||
104 | /** |
||
105 | * The query library to use. Default is Native |
||
106 | * |
||
107 | * @type string |
||
108 | */ |
||
109 | protected $queryLibrary = 'GameQ\\Query\\Native'; |
||
110 | |||
111 | /** |
||
112 | * Holds the instance of the queryLibrary |
||
113 | * |
||
114 | * @type \GameQ\Query\Core|null |
||
115 | */ |
||
116 | protected $query = null; |
||
117 | |||
118 | /** |
||
119 | * GameQ constructor. |
||
120 | * |
||
121 | * Do some checks as needed so this will operate |
||
122 | */ |
||
123 | 223 | public function __construct() |
|
131 | |||
132 | /** |
||
133 | * Get an option's value |
||
134 | * |
||
135 | * @param mixed $option |
||
136 | * |
||
137 | * @return mixed|null |
||
138 | */ |
||
139 | 216 | public function __get($option) |
|
144 | |||
145 | /** |
||
146 | * Set an option's value |
||
147 | * |
||
148 | * @param mixed $option |
||
149 | * @param mixed $value |
||
150 | * |
||
151 | * @return bool |
||
152 | */ |
||
153 | 218 | public function __set($option, $value) |
|
160 | |||
161 | /** |
||
162 | * Chainable call to __set, uses set as the actual setter |
||
163 | * |
||
164 | * @param mixed $var |
||
165 | * @param mixed $value |
||
166 | * |
||
167 | * @return $this |
||
168 | */ |
||
169 | 218 | public function setOption($var, $value) |
|
177 | |||
178 | /** |
||
179 | * Add a single server |
||
180 | * |
||
181 | * @param array $server_info |
||
182 | * |
||
183 | * @return $this |
||
184 | */ |
||
185 | 2 | public function addServer(array $server_info = []) |
|
193 | |||
194 | /** |
||
195 | * Add multiple servers in a single call |
||
196 | * |
||
197 | * @param array $servers |
||
198 | * |
||
199 | * @return $this |
||
200 | */ |
||
201 | 2 | public function addServers(array $servers = []) |
|
202 | { |
||
203 | |||
204 | // Loop through all the servers and add them |
||
205 | 2 | foreach ($servers as $server_info) { |
|
206 | 2 | $this->addServer($server_info); |
|
207 | 2 | } |
|
208 | |||
209 | 2 | return $this; // Make calls chainable |
|
210 | } |
||
211 | |||
212 | /** |
||
213 | * Add a set of servers from a file or an array of files. |
||
214 | * Supported formats: |
||
215 | * JSON |
||
216 | * |
||
217 | * @param array $files |
||
218 | * |
||
219 | * @return $this |
||
220 | * @throws \Exception |
||
221 | */ |
||
222 | 1 | public function addServersFromFiles($files = []) |
|
223 | { |
||
224 | |||
225 | // Since we expect an array let us turn a string (i.e. single file) into an array |
||
226 | 1 | if (!is_array($files)) { |
|
227 | 1 | $files = [$files]; |
|
228 | 1 | } |
|
229 | |||
230 | // Iterate over the file(s) and add them |
||
231 | 1 | foreach ($files as $file) { |
|
232 | // Check to make sure the file exists and we can read it |
||
233 | 1 | if (!file_exists($file) || !is_readable($file)) { |
|
234 | 1 | continue; |
|
235 | } |
||
236 | |||
237 | // See if this file is JSON |
||
238 | 1 | if (($servers = json_decode(file_get_contents($file), true)) === null |
|
239 | 1 | && json_last_error() !== JSON_ERROR_NONE |
|
240 | 1 | ) { |
|
241 | // Type not supported |
||
242 | 1 | continue; |
|
243 | } |
||
244 | |||
245 | // Add this list of servers |
||
246 | 1 | $this->addServers($servers); |
|
247 | 1 | } |
|
248 | |||
249 | 1 | return $this; |
|
250 | } |
||
251 | |||
252 | /** |
||
253 | * Clear all of the defined servers |
||
254 | * |
||
255 | * @return $this |
||
256 | */ |
||
257 | 2 | public function clearServers() |
|
265 | |||
266 | /** |
||
267 | * Add a filter to the processing list |
||
268 | * |
||
269 | * @param string $filterName |
||
270 | * @param array $options |
||
271 | * |
||
272 | * @return $this |
||
273 | */ |
||
274 | 3 | public function addFilter($filterName, $options = []) |
|
289 | |||
290 | /** |
||
291 | * Remove an added filter |
||
292 | * |
||
293 | * @param string $filterHash |
||
294 | * |
||
295 | * @return $this |
||
296 | */ |
||
297 | 216 | public function removeFilter($filterHash) |
|
298 | { |
||
299 | // Make lower case |
||
300 | 216 | $filterHash = strtolower($filterHash); |
|
301 | |||
302 | // Remove this filter if it has been defined |
||
303 | 216 | if (array_key_exists($filterHash, $this->options['filters'])) { |
|
304 | 3 | unset($this->options['filters'][$filterHash]); |
|
305 | 3 | } |
|
306 | |||
307 | 216 | unset($filterHash); |
|
308 | |||
309 | 216 | return $this; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * Return the list of applied filters |
||
314 | * |
||
315 | * @return array |
||
316 | */ |
||
317 | public function listFilters() |
||
321 | |||
322 | /** |
||
323 | * Main method used to actually process all of the added servers and return the information |
||
324 | * |
||
325 | * @return array |
||
326 | * @throws \Exception |
||
327 | */ |
||
328 | public function process() |
||
369 | |||
370 | /** |
||
371 | * Do server challenges, where required |
||
372 | */ |
||
373 | protected function doChallenges() |
||
456 | |||
457 | /** |
||
458 | * Run the actual queries and get the response(s) |
||
459 | */ |
||
460 | protected function doQueries() |
||
559 | |||
560 | /** |
||
561 | * Parse the response for a specific server |
||
562 | * |
||
563 | * @param \GameQ\Server $server |
||
564 | * |
||
565 | * @return array |
||
566 | * @throws \Exception |
||
567 | */ |
||
568 | 215 | protected function doParseResponse(Server $server) |
|
615 | |||
616 | /** |
||
617 | * Apply any filters to the results |
||
618 | * |
||
619 | * @param array $results |
||
620 | * @param \GameQ\Server $server |
||
621 | * |
||
622 | * @return array |
||
623 | */ |
||
624 | 2 | protected function doApplyFilters(array $results, Server $server) |
|
647 | } |
||
648 |
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.
You can also find more information in the “Code” section of your repository.