Complex classes like Xhgui_Profile 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 Xhgui_Profile, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
7 | class Xhgui_Profile |
||
8 | { |
||
9 | /** |
||
10 | * @const Key used for methods with no parent |
||
11 | */ |
||
12 | const NO_PARENT = '__xhgui_top__'; |
||
13 | |||
14 | protected $_data; |
||
15 | protected $_collapsed; |
||
16 | protected $_indexed; |
||
17 | protected $_visited; |
||
18 | |||
19 | protected $_keys = array('ct', 'wt', 'cpu', 'mu', 'pmu'); |
||
20 | protected $_exclusiveKeys = array('ewt', 'ecpu', 'emu', 'epmu'); |
||
21 | protected $_functionCount; |
||
22 | |||
23 | public function __construct(array $profile, $convert = true) |
||
36 | |||
37 | /** |
||
38 | * Convert the raw data into a flatter list that is easier to use. |
||
39 | * |
||
40 | * This removes some of the parentage detail as all calls of a given |
||
41 | * method are aggregated. We are not able to maintain a full tree structure |
||
42 | * in any case, as xhprof only keeps one level of detail. |
||
43 | * |
||
44 | * @return void |
||
45 | */ |
||
46 | protected function _process() |
||
72 | |||
73 | /** |
||
74 | * Sum up the values in $this->_keys; |
||
75 | * |
||
76 | * @param array $a The first set of profile data |
||
77 | * @param array $b The second set of profile data. |
||
78 | * @return array Merged profile data. |
||
79 | */ |
||
80 | protected function _sumKeys($a, $b) |
||
90 | |||
91 | protected function _diffKeys($a, $b, $includeSelf = true) |
||
102 | |||
103 | protected function _diffPercentKeys($a, $b, $includeSelf = true) |
||
119 | |||
120 | /** |
||
121 | * Get the profile run data. |
||
122 | * |
||
123 | * TODO remove this and move all the features using it into this/ |
||
124 | * other classes. |
||
125 | * |
||
126 | * @return array |
||
127 | */ |
||
128 | public function getProfile() |
||
132 | |||
133 | public function getId() |
||
137 | |||
138 | public function getDate() |
||
146 | |||
147 | /** |
||
148 | * Get meta data about the profile. Read's a . split path |
||
149 | * out of the meta data in a profile. For example `SERVER.REQUEST_TIME` |
||
150 | * |
||
151 | * @param string $key The dotted key to read. |
||
152 | * @return null|mixed Null on failure, otherwise the stored value. |
||
153 | */ |
||
154 | public function getMeta($key = null) |
||
170 | |||
171 | /** |
||
172 | * Read data from the profile run. |
||
173 | * |
||
174 | * @param string $key The function key name to read. |
||
175 | * @param string $metric The metric to read. |
||
176 | * @return null|float |
||
177 | */ |
||
178 | public function get($key, $metric = null) |
||
191 | |||
192 | /** |
||
193 | * Find a function matching a watched function. |
||
194 | * |
||
195 | * @param string $pattern The pattern to look for. |
||
196 | * @return null|array An list of matching functions |
||
197 | * or null. |
||
198 | */ |
||
199 | public function getWatched($pattern) |
||
217 | |||
218 | /** |
||
219 | * Find the parent and children method/functions for a given |
||
220 | * symbol. |
||
221 | * |
||
222 | * The parent/children arrays will contain all the callers + callees |
||
223 | * of the symbol given. The current index will give the total |
||
224 | * inclusive values for all properties. |
||
225 | * |
||
226 | * @param string $symbol The name of the function/method to find |
||
227 | * relatives for. |
||
228 | * @param string $metric The metric to compare $threshold with. |
||
229 | * @param float $threshold The threshold to exclude child functions at. Any |
||
230 | * function that represents less than this percentage of the current metric |
||
231 | * will be filtered out. |
||
232 | * @return array List of (parent, current, children) |
||
233 | */ |
||
234 | public function getRelatives($symbol, $metric = null, $threshold = 0) |
||
253 | |||
254 | /** |
||
255 | * Get the parent methods for a given symbol. |
||
256 | * |
||
257 | * @param string $symbol The name of the function/method to find |
||
258 | * parents for. |
||
259 | * @return array List of parents |
||
260 | */ |
||
261 | protected function _getParents($symbol) |
||
272 | |||
273 | /** |
||
274 | * Find symbols that are the children of the given name. |
||
275 | * |
||
276 | * @param string $symbol The name of the function to find children of. |
||
277 | * @param string $metric The metric to compare $threshold with. |
||
278 | * @param float $threshold The threshold to exclude functions at. Any |
||
279 | * function that represents less than |
||
280 | * @return array An array of child methods. |
||
281 | */ |
||
282 | protected function _getChildren($symbol, $metric = null, $threshold = 0) |
||
308 | |||
309 | /** |
||
310 | * Extracts a single dimension of data |
||
311 | * from a profile run. |
||
312 | * |
||
313 | * Useful for creating bar/column graphs. |
||
314 | * The profile data will be sorted by the column |
||
315 | * and then the $limit records will be extracted. |
||
316 | * |
||
317 | * @param string $dimension The dimension to extract |
||
318 | * @param int $limit Number of elements to pull |
||
319 | * @return array Array of data with name = function name and |
||
320 | * value = the dimension. |
||
321 | */ |
||
322 | public function extractDimension($dimension, $limit) |
||
335 | |||
336 | /** |
||
337 | * Generate the approximate exclusive values for each metric. |
||
338 | * |
||
339 | * We get a==>b as the name, we need a key for a and b in the array |
||
340 | * to get exclusive values for A we need to subtract the values of B (and any other children); |
||
341 | * call passing in the entire profile only, should return an array of |
||
342 | * functions with their regular timing, and exclusive numbers inside ['exclusive'] |
||
343 | * |
||
344 | * Consider: |
||
345 | * /---c---d---e |
||
346 | * a -/----b---d---e |
||
347 | * |
||
348 | * We have c==>d and b==>d, and in both instances d invokes e, yet we will |
||
349 | * have but a single d==>e result. This is a known and documented limitation of XHProf |
||
350 | * |
||
351 | * We have one d==>e entry, with some values, including ct=2 |
||
352 | * We also have c==>d and b==>d |
||
353 | * |
||
354 | * We should determine how many ==>d options there are, and equally |
||
355 | * split the cost of d==>e across them since d==>e represents the sum total of all calls. |
||
356 | * |
||
357 | * Notes: |
||
358 | * Function names are not unique, but we're merging them |
||
359 | * |
||
360 | * @return Xhgui_Profile A new instance with exclusive data set. |
||
361 | */ |
||
362 | public function calculateSelf() |
||
388 | |||
389 | /** |
||
390 | * Sort data by a dimension. |
||
391 | * |
||
392 | * @param string $dimension The dimension to sort by. |
||
393 | * @param array $data The data to sort. |
||
394 | * @return array The sorted data. |
||
395 | */ |
||
396 | public function sort($dimension, $data) |
||
407 | |||
408 | /** |
||
409 | * @param array $profileData |
||
410 | * @param array $filters |
||
411 | * |
||
412 | * @return array |
||
413 | */ |
||
414 | public function filter($profileData, $filters = []) |
||
426 | |||
427 | /** |
||
428 | * Split a key name into the parent==>child format. |
||
429 | * |
||
430 | * @param string $name The name to split. |
||
431 | * @return array An array of parent, child. parent will be null if there |
||
432 | * is no parent. |
||
433 | */ |
||
434 | public function splitName($name) |
||
442 | |||
443 | /** |
||
444 | * Get the total number of tracked function calls in this run. |
||
445 | * |
||
446 | * @return int |
||
447 | */ |
||
448 | public function getFunctionCount() |
||
460 | |||
461 | /** |
||
462 | * Compare this run to another run. |
||
463 | * |
||
464 | * @param Xhgui_Profile $head The other run to compare with |
||
465 | * @return array An array of comparison data. |
||
466 | */ |
||
467 | public function compare(Xhgui_Profile $head) |
||
500 | |||
501 | /** |
||
502 | * Get the max value for any give metric. |
||
503 | * |
||
504 | * @param string $metric The metric to get a max value for. |
||
505 | */ |
||
506 | protected function _maxValue($metric) |
||
519 | |||
520 | /** |
||
521 | * Return a structured array suitable for generating callgraph visualizations. |
||
522 | * |
||
523 | * Functions whose inclusive time is less than 2% of the total time will |
||
524 | * be excluded from the callgraph data. |
||
525 | * |
||
526 | * @return array |
||
527 | */ |
||
528 | public function getCallgraph($metric = 'wt', $threshold = 0.01) |
||
554 | |||
555 | protected function _callgraphData($parentName, $main, $metric, $threshold, $parentIndex = null) |
||
601 | |||
602 | public function toArray() |
||
606 | } |
||
607 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.