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 BitArray 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 BitArray, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class BitArray implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable |
||
28 | { |
||
29 | /** |
||
30 | * @var integer[] Number of bits for each value between 0 and 255 |
||
31 | */ |
||
32 | private static $count = [ |
||
33 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
||
34 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||
35 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||
36 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
37 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||
38 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
39 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
40 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||
41 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||
42 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
43 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
44 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||
45 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||
46 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||
47 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||
48 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
||
49 | ]; |
||
50 | |||
51 | /** |
||
52 | * @var integer[] Mask for restricting complements |
||
53 | */ |
||
54 | private static $restrict = [255, 1, 3, 7, 15, 31, 63, 127]; |
||
55 | |||
56 | /** |
||
57 | * @var string Underlying data |
||
58 | * |
||
59 | * @since 1.0.0 |
||
60 | */ |
||
61 | private $data; |
||
62 | |||
63 | /** |
||
64 | * @var integer Size of the bit array |
||
65 | * |
||
66 | * @since 1.0.0 |
||
67 | */ |
||
68 | private $size; |
||
69 | |||
70 | /** |
||
71 | * Create a new bit array of the given size |
||
72 | * |
||
73 | * @param integer $size The BitArray size |
||
74 | * |
||
75 | * @since 1.0.0 |
||
76 | */ |
||
77 | protected function __construct($size) |
||
82 | |||
83 | /** |
||
84 | * Clone a bitarray |
||
85 | * |
||
86 | * @return void |
||
87 | * |
||
88 | * @since 1.0.0 |
||
89 | */ |
||
90 | public function __clone() |
||
94 | |||
95 | /** |
||
96 | * Convert the object to a string |
||
97 | * |
||
98 | * @return string String representation of this object |
||
99 | * |
||
100 | * @since 1.0.0 |
||
101 | */ |
||
102 | public function __toString() |
||
116 | |||
117 | /** |
||
118 | * Magic get method |
||
119 | * |
||
120 | * @param string $property The property |
||
121 | * |
||
122 | * @throws \RuntimeException If the property does not exist |
||
123 | * |
||
124 | * @return mixed The value associated to the property |
||
125 | * |
||
126 | * @since 1.0.0 |
||
127 | */ |
||
128 | public function __get($property) |
||
140 | |||
141 | /** |
||
142 | * Test the existence of an index |
||
143 | * |
||
144 | * @param integer $offset The offset |
||
145 | * |
||
146 | * @return boolean The truth value |
||
147 | * |
||
148 | * @since 1.0.0 |
||
149 | */ |
||
150 | public function offsetExists($offset) |
||
154 | |||
155 | /** |
||
156 | * Get the truth value for an index |
||
157 | * |
||
158 | * @param integer $offset The offset |
||
159 | * |
||
160 | * @return boolean The truth value |
||
161 | * |
||
162 | * @throw \OutOfRangeException Argument index must be an positive integer lesser than the size |
||
163 | * |
||
164 | * @since 1.0.0 |
||
165 | */ |
||
166 | public function offsetGet($offset) |
||
177 | |||
178 | /** |
||
179 | * Set the truth value for an index |
||
180 | * |
||
181 | * @param integer $offset The offset |
||
182 | * @param boolean $value The truth value |
||
183 | * |
||
184 | * @return void |
||
185 | * |
||
186 | * @throw \OutOfRangeException Argument index must be an positive integer lesser than the size |
||
187 | * |
||
188 | * @since 1.0.0 |
||
189 | */ |
||
190 | public function offsetSet($offset, $value) |
||
210 | |||
211 | /** |
||
212 | * Unset the existence of an index |
||
213 | * |
||
214 | * @param integer $offset The index |
||
215 | * |
||
216 | * @return void |
||
217 | * |
||
218 | * @throw \RuntimeException Values cannot be unset |
||
219 | * |
||
220 | * @since 1.0.0 |
||
221 | */ |
||
222 | public function offsetUnset($offset) |
||
226 | |||
227 | /** |
||
228 | * Return the number of true bits |
||
229 | * |
||
230 | * @return integer The number of true bits |
||
231 | * |
||
232 | * @since 1.0.0 |
||
233 | */ |
||
234 | public function count() |
||
245 | |||
246 | /** |
||
247 | * Transform the object to an array |
||
248 | * |
||
249 | * @return array Array of values |
||
250 | * |
||
251 | * @since 1.1.0 |
||
252 | */ |
||
253 | public function toArray() |
||
264 | |||
265 | /** |
||
266 | * Serialize the object |
||
267 | * |
||
268 | * @return array Array of values |
||
269 | * |
||
270 | * @since 1.0.0 |
||
271 | */ |
||
272 | public function jsonSerialize() |
||
276 | |||
277 | /** |
||
278 | * Get an iterator |
||
279 | * |
||
280 | * @return Iterator Iterator |
||
281 | * |
||
282 | * @since 1.0.0 |
||
283 | */ |
||
284 | public function getIterator() |
||
288 | |||
289 | /** |
||
290 | * Return the size |
||
291 | * |
||
292 | * @return integer The size |
||
293 | * |
||
294 | * @since 1.0.0 |
||
295 | */ |
||
296 | public function size() |
||
300 | |||
301 | /** |
||
302 | * Create a new BitArray from an integer |
||
303 | * |
||
304 | * @param integer $size Size of the bitarray |
||
305 | * |
||
306 | * @return BitArray A new BitArray |
||
307 | * |
||
308 | * @since 1.0.0 |
||
309 | */ |
||
310 | public static function fromInteger($size) |
||
314 | |||
315 | /** |
||
316 | * Create a new BitArray from a traversable |
||
317 | * |
||
318 | * @param \Traversable $traversable A traversable and countable |
||
319 | * |
||
320 | * @return BitArray A new BitArray |
||
321 | * |
||
322 | * @since 1.0.0 |
||
323 | */ |
||
324 | View Code Duplication | public static function fromTraversable($traversable) |
|
353 | |||
354 | /** |
||
355 | * Create a new BitArray from a bit string |
||
356 | * |
||
357 | * @param string $string A bit string |
||
358 | * |
||
359 | * @return BitArray A new BitArray |
||
360 | * |
||
361 | * @since 1.0.0 |
||
362 | */ |
||
363 | View Code Duplication | public static function fromString($string) |
|
389 | |||
390 | /** |
||
391 | * Create a new BitArray from json |
||
392 | * |
||
393 | * @param string $json A json encoded value |
||
394 | * |
||
395 | * @return BitArray A new BitArray |
||
396 | * |
||
397 | * @since 1.0.0 |
||
398 | */ |
||
399 | public static function fromJson($json) |
||
403 | |||
404 | /** |
||
405 | * Create a new BitArray using a slice |
||
406 | * |
||
407 | * @param BitArray $bits A bitarray to get the slice |
||
408 | * @param int $offset If offset is non-negative, the slice will start at that offset in the bits argument. |
||
409 | * If offset is negative, the slice will start that far from the end of the bits argument. |
||
410 | * @param mixed $size If size is given and is positive, then the slice will have up to that many elements in it. |
||
411 | * If the bits argument is shorter than the size, then only the available elements will be present. |
||
412 | * If size is given and is negative then the slice will stop that many elements from the end of the bits argument. |
||
413 | * If it is omitted, then the slice will have everything from offset up until the end of the bits argument. |
||
414 | * |
||
415 | * @return BitArray A new BitArray |
||
416 | * |
||
417 | * @since 1.1.0 |
||
418 | */ |
||
419 | public static function fromSlice(BitArray $bits, $offset = 0, $size = null) |
||
470 | |||
471 | /** |
||
472 | * Create a new BitArray using the concat operation |
||
473 | * |
||
474 | * @param BitArray $bits1 A bitarray |
||
475 | * @param BitArray $bits2 A bitarray |
||
476 | * |
||
477 | * @return BitArray A new BitArray |
||
478 | * |
||
479 | * @since 1.1.0 |
||
480 | */ |
||
481 | public static function fromConcat(BitArray $bits1, BitArray $bits2) |
||
498 | |||
499 | /** |
||
500 | * Complement the bit array |
||
501 | * |
||
502 | * @return BitArray This object for chaining |
||
503 | * |
||
504 | * @since 1.0.0 |
||
505 | */ |
||
506 | public function applyComplement() |
||
523 | |||
524 | /** |
||
525 | * Or with an another bit array |
||
526 | * |
||
527 | * @param BitArray $bits A bit array |
||
528 | * |
||
529 | * @return BitArray This object for chaining |
||
530 | * |
||
531 | * @throw \InvalidArgumentException Argument must be of equal size |
||
532 | * |
||
533 | * @since 1.0.0 |
||
534 | */ |
||
535 | View Code Duplication | public function applyOr(BitArray $bits) |
|
553 | |||
554 | /** |
||
555 | * And with an another bit array |
||
556 | * |
||
557 | * @param BitArray $bits A bit array |
||
558 | * |
||
559 | * @return BitArray This object for chaining |
||
560 | * |
||
561 | * @throw \InvalidArgumentException Argument must be of equal size |
||
562 | * |
||
563 | * @since 1.0.0 |
||
564 | */ |
||
565 | View Code Duplication | public function applyAnd(BitArray $bits) |
|
583 | |||
584 | /** |
||
585 | * Xor with an another bit array |
||
586 | * |
||
587 | * @param BitArray $bits A bit array |
||
588 | * |
||
589 | * @return BitArray This object for chaining |
||
590 | * |
||
591 | * @throw \InvalidArgumentException Argument must be of equal size |
||
592 | * |
||
593 | * @since 1.0.0 |
||
594 | */ |
||
595 | View Code Duplication | public function applyXor(BitArray $bits) |
|
613 | } |
||
614 |
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.