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 Registry 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 Registry, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class Registry implements \JsonSerializable, \ArrayAccess, \IteratorAggregate, \Countable |
||
19 | { |
||
20 | /** |
||
21 | * Registry Object |
||
22 | * |
||
23 | * @var object |
||
24 | * @since 1.0 |
||
25 | */ |
||
26 | protected $data; |
||
27 | |||
28 | /** |
||
29 | * Flag if the Registry data object has been initialized |
||
30 | * |
||
31 | * @var boolean |
||
32 | * @since 1.5.2 |
||
33 | */ |
||
34 | protected $initialized = false; |
||
35 | |||
36 | /** |
||
37 | * Registry instances container. |
||
38 | * |
||
39 | * @var array |
||
40 | * @since 1.0 |
||
41 | * @deprecated 2.0 Object caching will no longer be supported |
||
42 | */ |
||
43 | protected static $instances = array(); |
||
44 | |||
45 | /** |
||
46 | * Path separator |
||
47 | * |
||
48 | * @var string |
||
49 | * @since 1.4.0 |
||
50 | */ |
||
51 | public $separator = '.'; |
||
52 | |||
53 | /** |
||
54 | * Constructor |
||
55 | * |
||
56 | * @param mixed $data The data to bind to the new Registry object. |
||
57 | * |
||
58 | * @since 1.0 |
||
59 | */ |
||
60 | public function __construct($data = null) |
||
75 | |||
76 | /** |
||
77 | * Magic function to clone the registry object. |
||
78 | * |
||
79 | * @return Registry |
||
80 | * |
||
81 | * @since 1.0 |
||
82 | */ |
||
83 | public function __clone() |
||
87 | |||
88 | /** |
||
89 | * Magic function to render this object as a string using default args of toString method. |
||
90 | * |
||
91 | * @return string |
||
92 | * |
||
93 | * @since 1.0 |
||
94 | */ |
||
95 | public function __toString() |
||
99 | |||
100 | /** |
||
101 | * Count elements of the data object |
||
102 | * |
||
103 | * @return integer The custom count as an integer. |
||
104 | * |
||
105 | * @link http://php.net/manual/en/countable.count.php |
||
106 | * @since 1.3.0 |
||
107 | */ |
||
108 | public function count() |
||
112 | |||
113 | /** |
||
114 | * Implementation for the JsonSerializable interface. |
||
115 | * Allows us to pass Registry objects to json_encode. |
||
116 | * |
||
117 | * @return object |
||
118 | * |
||
119 | * @since 1.0 |
||
120 | * @note The interface is only present in PHP 5.4 and up. |
||
121 | */ |
||
122 | public function jsonSerialize() |
||
126 | |||
127 | /** |
||
128 | * Sets a default value if not already assigned. |
||
129 | * |
||
130 | * @param string $key The name of the parameter. |
||
131 | * @param mixed $default An optional value for the parameter. |
||
132 | * |
||
133 | * @return mixed The value set, or the default if the value was not previously set (or null). |
||
134 | * |
||
135 | * @since 1.0 |
||
136 | */ |
||
137 | public function def($key, $default = '') |
||
144 | |||
145 | /** |
||
146 | * Check if a registry path exists. |
||
147 | * |
||
148 | * @param string $path Registry path (e.g. joomla.content.showauthor) |
||
149 | * |
||
150 | * @return boolean |
||
151 | * |
||
152 | * @since 1.0 |
||
153 | */ |
||
154 | public function exists($path) |
||
190 | |||
191 | /** |
||
192 | * Get a registry value. |
||
193 | * |
||
194 | * @param string $path Registry path (e.g. joomla.content.showauthor) |
||
195 | * @param mixed $default Optional default value, returned if the internal value is null. |
||
196 | * |
||
197 | * @return mixed Value of entry or null |
||
198 | * |
||
199 | * @since 1.0 |
||
200 | */ |
||
201 | public function get($path, $default = null) |
||
248 | |||
249 | /** |
||
250 | * Returns a reference to a global Registry object, only creating it |
||
251 | * if it doesn't already exist. |
||
252 | * |
||
253 | * This method must be invoked as: |
||
254 | * <pre>$registry = Registry::getInstance($id);</pre> |
||
255 | * |
||
256 | * @param string $id An ID for the registry instance |
||
257 | * |
||
258 | * @return Registry The Registry object. |
||
259 | * |
||
260 | * @since 1.0 |
||
261 | * @deprecated 2.0 Instantiate a new Registry instance instead |
||
262 | */ |
||
263 | public static function getInstance($id) |
||
272 | |||
273 | /** |
||
274 | * Gets this object represented as an ArrayIterator. |
||
275 | * |
||
276 | * This allows the data properties to be accessed via a foreach statement. |
||
277 | * |
||
278 | * @return \ArrayIterator This object represented as an ArrayIterator. |
||
279 | * |
||
280 | * @see IteratorAggregate::getIterator() |
||
281 | * @since 1.3.0 |
||
282 | */ |
||
283 | public function getIterator() |
||
287 | |||
288 | /** |
||
289 | * Load an associative array of values into the default namespace |
||
290 | * |
||
291 | * @param array $array Associative array of value to load |
||
292 | * @param boolean $flattened Load from a one-dimensional array |
||
293 | * @param string $separator The key separator |
||
294 | * |
||
295 | * @return Registry Return this object to support chaining. |
||
296 | * |
||
297 | * @since 1.0 |
||
298 | */ |
||
299 | public function loadArray($array, $flattened = false, $separator = null) |
||
315 | |||
316 | /** |
||
317 | * Load the public variables of the object into the default namespace. |
||
318 | * |
||
319 | * @param object $object The object holding the publics to load |
||
320 | * |
||
321 | * @return Registry Return this object to support chaining. |
||
322 | * |
||
323 | * @since 1.0 |
||
324 | */ |
||
325 | public function loadObject($object) |
||
331 | |||
332 | /** |
||
333 | * Load the contents of a file into the registry |
||
334 | * |
||
335 | * @param string $file Path to file to load |
||
336 | * @param string $format Format of the file [optional: defaults to JSON] |
||
337 | * @param array $options Options used by the formatter |
||
338 | * |
||
339 | * @return Registry Return this object to support chaining. |
||
340 | * |
||
341 | * @since 1.0 |
||
342 | */ |
||
343 | public function loadFile($file, $format = 'JSON', $options = array()) |
||
349 | |||
350 | /** |
||
351 | * Load a string into the registry |
||
352 | * |
||
353 | * @param string $data String to load into the registry |
||
354 | * @param string $format Format of the string |
||
355 | * @param array $options Options used by the formatter |
||
356 | * |
||
357 | * @return Registry Return this object to support chaining. |
||
358 | * |
||
359 | * @since 1.0 |
||
360 | */ |
||
361 | public function loadString($data, $format = 'JSON', $options = array()) |
||
381 | |||
382 | /** |
||
383 | * Merge a Registry object into this one |
||
384 | * |
||
385 | * @param Registry $source Source Registry object to merge. |
||
386 | * @param boolean $recursive True to support recursive merge the children values. |
||
387 | * |
||
388 | * @return Registry Return this object to support chaining. |
||
389 | * |
||
390 | * @since 1.0 |
||
391 | */ |
||
392 | public function merge($source, $recursive = false) |
||
403 | |||
404 | /** |
||
405 | * Method to extract a sub-registry from path |
||
406 | * |
||
407 | * @param string $path Registry path (e.g. joomla.content.showauthor) |
||
408 | * |
||
409 | * @return Registry|null Registry object if data is present |
||
410 | * |
||
411 | * @since 1.2.0 |
||
412 | */ |
||
413 | public function extract($path) |
||
424 | |||
425 | /** |
||
426 | * Checks whether an offset exists in the iterator. |
||
427 | * |
||
428 | * @param mixed $offset The array offset. |
||
429 | * |
||
430 | * @return boolean True if the offset exists, false otherwise. |
||
431 | * |
||
432 | * @since 1.0 |
||
433 | */ |
||
434 | public function offsetExists($offset) |
||
438 | |||
439 | /** |
||
440 | * Gets an offset in the iterator. |
||
441 | * |
||
442 | * @param mixed $offset The array offset. |
||
443 | * |
||
444 | * @return mixed The array value if it exists, null otherwise. |
||
445 | * |
||
446 | * @since 1.0 |
||
447 | */ |
||
448 | public function offsetGet($offset) |
||
452 | |||
453 | /** |
||
454 | * Sets an offset in the iterator. |
||
455 | * |
||
456 | * @param mixed $offset The array offset. |
||
457 | * @param mixed $value The array value. |
||
458 | * |
||
459 | * @return void |
||
460 | * |
||
461 | * @since 1.0 |
||
462 | */ |
||
463 | public function offsetSet($offset, $value) |
||
467 | |||
468 | /** |
||
469 | * Unsets an offset in the iterator. |
||
470 | * |
||
471 | * @param mixed $offset The array offset. |
||
472 | * |
||
473 | * @return void |
||
474 | * |
||
475 | * @since 1.0 |
||
476 | */ |
||
477 | public function offsetUnset($offset) |
||
481 | |||
482 | /** |
||
483 | * Set a registry value. |
||
484 | * |
||
485 | * @param string $path Registry Path (e.g. joomla.content.showauthor) |
||
486 | * @param mixed $value Value of entry |
||
487 | * @param string $separator The key separator |
||
488 | * |
||
489 | * @return mixed The value of the that has been set. |
||
490 | * |
||
491 | * @since 1.0 |
||
492 | */ |
||
493 | public function set($path, $value, $separator = null) |
||
561 | |||
562 | /** |
||
563 | * Append value to a path in registry |
||
564 | * |
||
565 | * @param string $path Parent registry Path (e.g. joomla.content.showauthor) |
||
566 | * @param mixed $value Value of entry |
||
567 | * |
||
568 | * @return mixed The value of the that has been set. |
||
569 | * |
||
570 | * @since 1.4.0 |
||
571 | */ |
||
572 | public function append($path, $value) |
||
626 | |||
627 | /** |
||
628 | * Transforms a namespace to an array |
||
629 | * |
||
630 | * @return array An associative array holding the namespace data |
||
631 | * |
||
632 | * @since 1.0 |
||
633 | */ |
||
634 | public function toArray() |
||
638 | |||
639 | /** |
||
640 | * Transforms a namespace to an object |
||
641 | * |
||
642 | * @return object An an object holding the namespace data |
||
643 | * |
||
644 | * @since 1.0 |
||
645 | */ |
||
646 | public function toObject() |
||
650 | |||
651 | /** |
||
652 | * Get a namespace in a given string format |
||
653 | * |
||
654 | * @param string $format Format to return the string in |
||
655 | * @param mixed $options Parameters used by the formatter, see formatters for more info |
||
656 | * |
||
657 | * @return string Namespace in string format |
||
658 | * |
||
659 | * @since 1.0 |
||
660 | */ |
||
661 | public function toString($format = 'JSON', $options = array()) |
||
668 | |||
669 | /** |
||
670 | * Method to recursively bind data to a parent object. |
||
671 | * |
||
672 | * @param object $parent The parent object on which to attach the data values. |
||
673 | * @param mixed $data An array or object of data to bind to the parent object. |
||
674 | * @param boolean $recursive True to support recursive bindData. |
||
675 | * @param boolean $allowNull True to allow null values. |
||
676 | * |
||
677 | * @return void |
||
678 | * |
||
679 | * @since 1.0 |
||
680 | */ |
||
681 | protected function bindData($parent, $data, $recursive = true, $allowNull = true) |
||
713 | |||
714 | /** |
||
715 | * Method to recursively convert an object of data to an array. |
||
716 | * |
||
717 | * @param object $data An object of data to return as an array. |
||
718 | * |
||
719 | * @return array Array representation of the input object. |
||
720 | * |
||
721 | * @since 1.0 |
||
722 | */ |
||
723 | protected function asArray($data) |
||
746 | |||
747 | /** |
||
748 | * Dump to one dimension array. |
||
749 | * |
||
750 | * @param string $separator The key separator. |
||
751 | * |
||
752 | * @return string[] Dumped array. |
||
753 | * |
||
754 | * @since 1.3.0 |
||
755 | */ |
||
756 | public function flatten($separator = null) |
||
769 | |||
770 | /** |
||
771 | * Method to recursively convert data to one dimension array. |
||
772 | * |
||
773 | * @param string $separator The key separator. |
||
774 | * @param array|object $data Data source of this scope. |
||
775 | * @param array &$array The result array, it is pass by reference. |
||
776 | * @param string $prefix Last level key prefix. |
||
777 | * |
||
778 | * @return void |
||
779 | * |
||
780 | * @since 1.3.0 |
||
781 | */ |
||
782 | protected function toFlatten($separator = null, $data = null, &$array = array(), $prefix = '') |
||
805 | } |
||
806 |
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.