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 TPriorityMap 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 TPriorityMap, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
62 | class TPriorityMap extends TMap |
||
63 | { |
||
64 | /** |
||
65 | * @var bool indicates if the _d is currently ordered. |
||
66 | */ |
||
67 | private $_o = false; |
||
68 | /** |
||
69 | * @var array cached flattened internal data storage |
||
70 | */ |
||
71 | private $_fd; |
||
72 | /** |
||
73 | * @var int number of items contain within the map |
||
74 | */ |
||
75 | private $_c = 0; |
||
76 | /** |
||
77 | * @var numeric the default priority of items without specified priorities |
||
78 | */ |
||
79 | private $_dp = 10; |
||
80 | /** |
||
81 | * @var int the precision of the numeric priorities within this priority list. |
||
82 | */ |
||
83 | private $_p = 8; |
||
84 | |||
85 | /** |
||
86 | * Constructor. |
||
87 | * Initializes the array with an array or an iterable object. |
||
88 | * @param null|array|Iterator|map|TPriorityMap $data the intial data. Default is null, meaning no initialization. |
||
89 | * @param bool $readOnly whether the list is read-only |
||
90 | * @param numeric $defaultPriority the default priority of items without specified priorities. |
||
91 | * @param int $precision the precision of the numeric priorities |
||
92 | * @throws TInvalidDataTypeException If data is not null and neither an array nor an iterator. |
||
93 | */ |
||
94 | 53 | View Code Duplication | public function __construct($data = null, $readOnly = false, $defaultPriority = 10, $precision = 8) |
103 | |||
104 | /** |
||
105 | * @return numeric gets the default priority of inserted items without a specified priority |
||
106 | */ |
||
107 | 53 | public function getDefaultPriority() |
|
111 | |||
112 | /** |
||
113 | * This must be called internally or when instantiated. |
||
114 | * @param numeric $value sets the default priority of inserted items without a specified priority |
||
115 | */ |
||
116 | 53 | protected function setDefaultPriority($value) |
|
120 | |||
121 | /** |
||
122 | * @return int The precision of numeric priorities, defaults to 8 |
||
123 | */ |
||
124 | 2 | public function getPrecision() |
|
128 | |||
129 | /** |
||
130 | * This must be called internally or when instantiated. |
||
131 | * @param int $value The precision of numeric priorities. |
||
132 | */ |
||
133 | 53 | protected function setPrecision($value) |
|
137 | |||
138 | /** |
||
139 | * Returns an iterator for traversing the items in the map. |
||
140 | * This method is required by the interface \IteratorAggregate. |
||
141 | * @return Iterator an iterator for traversing the items in the map. |
||
142 | */ |
||
143 | 2 | public function getIterator() |
|
147 | |||
148 | |||
149 | /** |
||
150 | * Orders the priority list internally. |
||
151 | */ |
||
152 | 48 | protected function sortPriorities() |
|
159 | |||
160 | /** |
||
161 | * This flattens the priority map into a flat array [0,...,n-1] |
||
162 | * @return array array of items in the list in priority and index order |
||
163 | */ |
||
164 | 42 | View Code Duplication | protected function flattenPriorities() |
177 | |||
178 | /** |
||
179 | * @return int the number of items in the map |
||
180 | */ |
||
181 | 20 | public function getCount() |
|
185 | |||
186 | /** |
||
187 | * Gets the number of items at a priority within the map. |
||
188 | * @param null|numeric $priority optional priority at which to count items. if no parameter, |
||
189 | * it will be set to the default {@link getDefaultPriority} |
||
190 | * @return int the number of items in the map at the specified priority |
||
191 | */ |
||
192 | View Code Duplication | public function getPriorityCount($priority = null) |
|
204 | |||
205 | /** |
||
206 | * This returns a list of the priorities within this map, ordered lowest to highest. |
||
207 | * @return array the array of priority numerics in decreasing priority order |
||
208 | */ |
||
209 | 3 | public function getPriorities() |
|
214 | |||
215 | /** |
||
216 | * Returns the keys within the map ordered through the priority of each key-value pair |
||
217 | * @return array the key list |
||
218 | */ |
||
219 | 1 | public function getKeys() |
|
223 | |||
224 | /** |
||
225 | * Returns the item with the specified key. If a priority is specified, only items |
||
226 | * within that specific priority will be selected |
||
227 | * @param mixed $key the key |
||
228 | * @param mixed $priority the priority. null is the default priority, false is any priority, |
||
229 | * and numeric is a specific priority. default: false, any priority. |
||
230 | * @return mixed the element at the offset, null if no element is found at the offset |
||
231 | */ |
||
232 | 29 | public function itemAt($key, $priority = false) |
|
245 | |||
246 | /** |
||
247 | * This changes an item's priority. Specify the item and the new priority. |
||
248 | * This method is exactly the same as {@link offsetGet}. |
||
249 | * @param mixed $key the key |
||
250 | * @param null|numeric $priority the priority. default: null, filled in with the default priority numeric. |
||
251 | * @return numeric old priority of the item |
||
252 | */ |
||
253 | 1 | public function setPriorityAt($key, $priority = null) |
|
267 | |||
268 | /** |
||
269 | * Gets all the items at a specific priority. |
||
270 | * @param null|numeric $priority priority of the items to get. Defaults to null, filled in with the default priority, if left blank. |
||
271 | * @return array all items at priority in index order, null if there are no items at that priority |
||
272 | */ |
||
273 | 3 | View Code Duplication | public function itemsAtPriority($priority = null) |
282 | |||
283 | /** |
||
284 | * Returns the priority of a particular item within the map. This searches the map for the item. |
||
285 | * @param mixed $item item to look for within the map |
||
286 | * @return numeric priority of the item in the map |
||
287 | */ |
||
288 | 2 | public function priorityOf($item) |
|
298 | |||
299 | /** |
||
300 | * Retutrns the priority of an item at a particular flattened index. |
||
301 | * @param int $key index of the item within the map |
||
302 | * @return numeric priority of the item in the map |
||
303 | */ |
||
304 | 3 | public function priorityAt($key) |
|
314 | |||
315 | /** |
||
316 | * Adds an item into the map. A third parameter may be used to set the priority |
||
317 | * of the item within the map. Priority is primarily used during when flattening |
||
318 | * the map into an array where order may be and important factor of the key-value |
||
319 | * pairs within the array. |
||
320 | * Note, if the specified key already exists, the old value will be overwritten. |
||
321 | * No duplicate keys are allowed regardless of priority. |
||
322 | * @param mixed $key |
||
323 | * @param mixed $value |
||
324 | * @param null|numeric $priority default: null, filled in with default priority |
||
325 | * @throws TInvalidOperationException if the map is read-only |
||
326 | * @return numeric priority at which the pair was added |
||
327 | */ |
||
328 | 53 | public function add($key, $value, $priority = null) |
|
358 | |||
359 | /** |
||
360 | * Removes an item from the map by its key. If no priority, or false, is specified |
||
361 | * then priority is irrelevant. If null is used as a parameter for priority, then |
||
362 | * the priority will be the default priority. If a priority is specified, or |
||
363 | * the default priority is specified, only key-value pairs in that priority |
||
364 | * will be affected. |
||
365 | * @param mixed $key the key of the item to be removed |
||
366 | * @param null|false|numeric $priority priority. False is any priority, null is the |
||
367 | * default priority, and numeric is a specific priority |
||
368 | * @throws TInvalidOperationException if the map is read-only |
||
369 | * @return mixed the removed value, null if no such key exists. |
||
370 | */ |
||
371 | 26 | public function remove($key, $priority = false) |
|
414 | |||
415 | /** |
||
416 | * Removes all items in the map. {@link remove} is called on all items. |
||
417 | */ |
||
418 | 3 | public function clear() |
|
426 | |||
427 | /** |
||
428 | * @param mixed $key the key |
||
429 | * @return bool whether the map contains an item with the specified key |
||
430 | */ |
||
431 | 31 | public function contains($key) |
|
436 | |||
437 | /** |
||
438 | * When the map is flattened into an array, the priorities are taken into |
||
439 | * account and elements of the map are ordered in the array according to |
||
440 | * their priority. |
||
441 | * @return array the list of items in array |
||
442 | */ |
||
443 | 30 | public function toArray() |
|
447 | |||
448 | /** |
||
449 | * Combines the map elements which have a priority below the parameter value |
||
450 | * @param numeric $priority the cut-off priority. All items of priority less than this are returned. |
||
451 | * @param bool $inclusive whether or not the input cut-off priority is inclusive. Default: false, not inclusive. |
||
452 | * @return array the array of priorities keys with values of arrays of items that are below a specified priority. |
||
453 | * The priorities are sorted so important priorities, lower numerics, are first. |
||
454 | */ |
||
455 | 1 | View Code Duplication | public function toArrayBelowPriority($priority, $inclusive = false) |
467 | |||
468 | /** |
||
469 | * Combines the map elements which have a priority above the parameter value |
||
470 | * @param numeric $priority the cut-off priority. All items of priority greater than this are returned. |
||
471 | * @param bool $inclusive whether or not the input cut-off priority is inclusive. Default: true, inclusive. |
||
472 | * @return array the array of priorities keys with values of arrays of items that are above a specified priority. |
||
473 | * The priorities are sorted so important priorities, lower numerics, are first. |
||
474 | */ |
||
475 | 1 | View Code Duplication | public function toArrayAbovePriority($priority, $inclusive = true) |
487 | |||
488 | /** |
||
489 | * Copies iterable data into the map. |
||
490 | * Note, existing data in the map will be cleared first. |
||
491 | * @param array|TPriorityMap|Traversable $data the data to be copied from, must be an array, object implementing |
||
492 | * @throws TInvalidDataTypeException If data is neither an array nor an iterator. |
||
493 | */ |
||
494 | 6 | View Code Duplication | public function copyFrom($data) |
516 | |||
517 | /** |
||
518 | * Merges iterable data into the map. |
||
519 | * Existing data in the map will be kept and overwritten if the keys are the same. |
||
520 | * @param array|TPriorityMap|Traversable $data the data to be merged with, must be an array, |
||
521 | * object implementing Traversable, or a TPriorityMap |
||
522 | * @throws TInvalidDataTypeException If data is neither an array nor an iterator. |
||
523 | */ |
||
524 | 2 | View Code Duplication | public function mergeWith($data) |
540 | } |
||
541 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.