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 Coollection 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 Coollection, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 20 | class Coollection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable |
||
| 21 | { |
||
| 22 | use Macroable { |
||
| 23 | __call as __callMacro; |
||
| 24 | } |
||
| 25 | |||
| 26 | /** |
||
| 27 | * Consants |
||
| 28 | */ |
||
| 29 | const NOT_FOUND = '!__NOT__FOUND__!'; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * The items contained in the collection. |
||
| 33 | * |
||
| 34 | * @var array |
||
| 35 | */ |
||
| 36 | protected $items; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Raise exception on null. |
||
| 40 | * |
||
| 41 | * @static boolean |
||
| 42 | */ |
||
| 43 | public static $raiseExceptionOnNull = true; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * The methods that can be proxied. |
||
| 47 | * |
||
| 48 | * @var array |
||
| 49 | */ |
||
| 50 | protected static $proxies = [ |
||
| 51 | 'average', 'avg', 'contains', 'each', 'every', 'filter', 'first', 'flatMap', |
||
| 52 | 'keyBy', 'map', 'partition', 'reject', 'sortBy', 'sortByDesc', 'sum', |
||
| 53 | ]; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * The methods that must return array. |
||
| 57 | * |
||
| 58 | * @var array |
||
| 59 | */ |
||
| 60 | protected static $returnArray = [ |
||
| 61 | 'toArray', 'jsonSerialize', 'unwrap', |
||
| 62 | ]; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Cache __toArray results. |
||
| 66 | * |
||
| 67 | * @var array |
||
| 68 | */ |
||
| 69 | protected $cache = []; |
||
| 70 | |||
| 71 | /** |
||
| 72 | * Create a new coollection. |
||
| 73 | * |
||
| 74 | * @param mixed $items |
||
| 75 | */ |
||
| 76 | 120 | public function __construct($items = []) |
|
| 80 | |||
| 81 | /** |
||
| 82 | * Transfer calls to Illuminate\Collection. |
||
| 83 | * |
||
| 84 | * @param $name |
||
| 85 | * @param $arguments |
||
| 86 | * @return mixed|static |
||
| 87 | */ |
||
| 88 | 120 | public function __call($name, $arguments) |
|
| 96 | |||
| 97 | /** |
||
| 98 | * Transfer calls to Illuminate\Collection. |
||
| 99 | * |
||
| 100 | * @param $name |
||
| 101 | * @param $arguments |
||
| 102 | * @return mixed|static |
||
| 103 | */ |
||
| 104 | 120 | public function call($name, $arguments = []) |
|
| 113 | |||
| 114 | /** |
||
| 115 | * Get the collection of items as a plain array. |
||
| 116 | * |
||
| 117 | * @param $value |
||
| 118 | * @return Coollection |
||
| 119 | */ |
||
| 120 | 120 | View Code Duplication | public function coollectizeItems($value) |
| 138 | |||
| 139 | /** |
||
| 140 | * Get the collection of items as a plain array. |
||
| 141 | * |
||
| 142 | * @return array |
||
| 143 | */ |
||
| 144 | 120 | public function toArray() |
|
| 150 | |||
| 151 | /** |
||
| 152 | * Dynamically access collection proxies. |
||
| 153 | * |
||
| 154 | * @param string $key |
||
| 155 | * @return mixed|static |
||
| 156 | * |
||
| 157 | * @throws \Exception |
||
| 158 | */ |
||
| 159 | 94 | public function __get($key) |
|
| 177 | |||
| 178 | /** |
||
| 179 | * Recursive toArray(). |
||
| 180 | * |
||
| 181 | * @param $value |
||
| 182 | * @return array |
||
| 183 | */ |
||
| 184 | 120 | View Code Duplication | public function __toArray($value = null) |
| 202 | |||
| 203 | /** |
||
| 204 | * Get an item from the collection by key. |
||
| 205 | * |
||
| 206 | * @param mixed $key |
||
| 207 | * @param mixed $default |
||
| 208 | * @return mixed |
||
| 209 | */ |
||
| 210 | 4 | public function get($key, $default = null) |
|
| 222 | |||
| 223 | /** |
||
| 224 | * Results array of items from Collection or Arrayable. |
||
| 225 | * |
||
| 226 | * @param mixed $items |
||
| 227 | * @return array |
||
| 228 | */ |
||
| 229 | 120 | protected function getArrayableItems($items) |
|
| 249 | |||
| 250 | /** |
||
| 251 | * Get an array as a key. |
||
| 252 | * |
||
| 253 | * @param $key |
||
| 254 | * @return mixed|string |
||
| 255 | */ |
||
| 256 | 94 | private function getArrayKey($key) |
|
| 278 | |||
| 279 | /** |
||
| 280 | * Transform string to snake case. |
||
| 281 | * |
||
| 282 | * @param $string |
||
| 283 | * @return string |
||
| 284 | */ |
||
| 285 | 94 | public function snakeCase($string) |
|
| 289 | |||
| 290 | /** |
||
| 291 | * Transform anything to string case. |
||
| 292 | * |
||
| 293 | * @param $string |
||
| 294 | * @return string |
||
| 295 | */ |
||
| 296 | 94 | public function stringCase($string) |
|
| 302 | |||
| 303 | /** |
||
| 304 | * Transform anything to kebab case. |
||
| 305 | * |
||
| 306 | * @param $string |
||
| 307 | * @return string |
||
| 308 | */ |
||
| 309 | 94 | public function kebabCase($string) |
|
| 315 | |||
| 316 | /** |
||
| 317 | * Transform anything to camel case. |
||
| 318 | * |
||
| 319 | * @param $string |
||
| 320 | * @return string |
||
| 321 | */ |
||
| 322 | 94 | public function camelCase($string) |
|
| 326 | |||
| 327 | /** |
||
| 328 | * Get a property by name. |
||
| 329 | * |
||
| 330 | * @param $key |
||
| 331 | * @return string|static |
||
| 332 | */ |
||
| 333 | 94 | private function getByPropertyName($key) |
|
| 345 | |||
| 346 | /** |
||
| 347 | * Execute a closure via Laravel's Collection |
||
| 348 | * |
||
| 349 | * @param $closure |
||
| 350 | * @param null $method |
||
| 351 | * @return mixed |
||
| 352 | */ |
||
| 353 | 120 | private function runViaLaravelCollection($closure, $method = null) |
|
| 367 | |||
| 368 | /** |
||
| 369 | * Does the method must return an array? |
||
| 370 | * |
||
| 371 | * @param $method |
||
| 372 | * @return bool |
||
| 373 | */ |
||
| 374 | 120 | public function methodMustReturnArray($method) |
|
| 378 | |||
| 379 | /** |
||
| 380 | * Raise exception on null setter. |
||
| 381 | * |
||
| 382 | * @param bool $raiseExceptionOnNull |
||
| 383 | */ |
||
| 384 | 3 | public static function setRaiseExceptionOnNull(bool $raiseExceptionOnNull) |
|
| 388 | |||
| 389 | /** |
||
| 390 | * Check if value is arrayable |
||
| 391 | * |
||
| 392 | * @param mixed $items |
||
| 393 | * @return bool |
||
| 394 | */ |
||
| 395 | 120 | protected function isArrayable($items) |
|
| 406 | |||
| 407 | /** |
||
| 408 | * Wrap on static if the value is arrayable. |
||
| 409 | * |
||
| 410 | * @param $value |
||
| 411 | * @return static |
||
| 412 | */ |
||
| 413 | 100 | protected function __wrap($value) |
|
| 423 | |||
| 424 | /** |
||
| 425 | * Determine if an item exists at an offset. |
||
| 426 | * |
||
| 427 | * @param mixed $key |
||
| 428 | * @return bool |
||
| 429 | */ |
||
| 430 | 4 | public function offsetExists($key) |
|
| 434 | |||
| 435 | /** |
||
| 436 | * Get an item at a given offset. |
||
| 437 | * |
||
| 438 | * @param mixed $key |
||
| 439 | * @return mixed |
||
| 440 | */ |
||
| 441 | 13 | public function offsetGet($key) |
|
| 449 | |||
| 450 | /** |
||
| 451 | * Set the item at a given offset. |
||
| 452 | * |
||
| 453 | * @param mixed $key |
||
| 454 | * @param mixed $value |
||
| 455 | * @return void |
||
| 456 | */ |
||
| 457 | 3 | public function offsetSet($key, $value) |
|
| 465 | |||
| 466 | /** |
||
| 467 | * Unset the item at a given offset. |
||
| 468 | * |
||
| 469 | * @param string $key |
||
| 470 | * @return void |
||
| 471 | */ |
||
| 472 | 2 | public function offsetUnset($key) |
|
| 476 | |||
| 477 | /** |
||
| 478 | * @param $items |
||
| 479 | * @return array|Coollection |
||
| 480 | * @internal param $originalCallback |
||
| 481 | */ |
||
| 482 | 120 | public function coollectizeCallbacks($items, $method) |
|
| 495 | |||
| 496 | /** |
||
| 497 | * @param $originalCallback |
||
| 498 | * @return callable |
||
| 499 | */ |
||
| 500 | 99 | public function coollectizeCallback(callable $originalCallback = null) |
|
| 508 | |||
| 509 | /** |
||
| 510 | * @param $originalCallback |
||
| 511 | * @return callable |
||
| 512 | */ |
||
| 513 | 1 | public function coollectizeCallbackForReduce(callable $originalCallback) |
|
| 522 | |||
| 523 | /** |
||
| 524 | * Overwrite the original array with the |
||
| 525 | * |
||
| 526 | * @param $overwrite |
||
| 527 | * @return Coollection |
||
| 528 | */ |
||
| 529 | 1 | public function overwrite($overwrite) |
|
| 535 | |||
| 536 | /** |
||
| 537 | * Convert the object to its JSON representation. |
||
| 538 | * |
||
| 539 | * @param int $options |
||
| 540 | * @return string |
||
| 541 | */ |
||
| 542 | 1 | public function toJson($options = 0) |
|
| 546 | |||
| 547 | /** |
||
| 548 | * Specify data which should be serialized to JSON |
||
| 549 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php |
||
| 550 | * @return mixed data which can be serialized by <b>json_encode</b>, |
||
| 551 | * which is a value of any type other than a resource. |
||
| 552 | * @since 5.4.0 |
||
| 553 | */ |
||
| 554 | 1 | public function jsonSerialize() |
|
| 558 | |||
| 559 | /** |
||
| 560 | * Count elements of an object |
||
| 561 | * @link http://php.net/manual/en/countable.count.php |
||
| 562 | * @return int The custom count as an integer. |
||
| 563 | * </p> |
||
| 564 | * <p> |
||
| 565 | * The return value is cast to an integer. |
||
| 566 | * @since 5.1.0 |
||
| 567 | */ |
||
| 568 | 12 | public function count() |
|
| 572 | |||
| 573 | /** |
||
| 574 | * Retrieve an external iterator |
||
| 575 | * @link http://php.net/manual/en/iteratoraggregate.getiterator.php |
||
| 576 | * @return Traversable An instance of an object implementing <b>Iterator</b> or |
||
| 577 | * <b>Traversable</b> |
||
| 578 | * @since 5.0.0 |
||
| 579 | */ |
||
| 580 | 2 | public function getIterator() |
|
| 584 | |||
| 585 | /** |
||
| 586 | * Sort by key. |
||
| 587 | * |
||
| 588 | * @return Coollection |
||
| 589 | */ |
||
| 590 | 1 | public function sortByKey() |
|
| 598 | |||
| 599 | /** |
||
| 600 | * Recursively Sort by key. |
||
| 601 | * |
||
| 602 | * @return Coollection |
||
| 603 | */ |
||
| 604 | 2 | public function sortByKeysRecursive() |
|
| 612 | |||
| 613 | /** |
||
| 614 | * Get raw items. |
||
| 615 | * |
||
| 616 | * @return array |
||
| 617 | */ |
||
| 618 | 120 | public function getItems() |
|
| 622 | |||
| 623 | /** |
||
| 624 | * Dynamically check a property exists on the underlying object. |
||
| 625 | * |
||
| 626 | * @param mixed $name |
||
| 627 | * @return bool |
||
| 628 | */ |
||
| 629 | public function __isset($name) |
||
| 635 | } |
||
| 636 |
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.