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 AbstractHelper 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 AbstractHelper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | abstract class AbstractHelper extends \Zend\View\Helper\AbstractHtmlElement implements |
||
41 | EventManagerAwareInterface, |
||
42 | HelperInterface, |
||
43 | ServiceLocatorAwareInterface, |
||
44 | TranslatorAwareInterface |
||
45 | { |
||
46 | |||
47 | use TranslatorAwareInterfaceTrait; |
||
48 | use ComponentClassnamesTrait; |
||
49 | use ComponentAttributesTrait; |
||
50 | use ComponentServiceManagersTrait; |
||
51 | use ComponentAclTrait; |
||
52 | use ComponentNavigationTrait; |
||
53 | |||
54 | // |
||
55 | // component related vars/properties/providers/services... |
||
56 | // |
||
57 | |||
58 | /** |
||
59 | * component's tag-name |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | protected $tagname = 'div'; |
||
64 | |||
65 | |||
66 | /** |
||
67 | * component's header |
||
68 | * |
||
69 | * @var mixed |
||
70 | */ |
||
71 | protected $header = null; |
||
72 | |||
73 | /** |
||
74 | * component's footer |
||
75 | * |
||
76 | * @var mixed |
||
77 | */ |
||
78 | protected $footer = null; |
||
79 | |||
80 | /** |
||
81 | * component's main content |
||
82 | * |
||
83 | * @var string|array |
||
84 | */ |
||
85 | protected $content = ''; |
||
86 | |||
87 | /** |
||
88 | * component's size attributes |
||
89 | * |
||
90 | * @var string|array |
||
91 | */ |
||
92 | protected $size = ''; |
||
93 | |||
94 | |||
95 | |||
96 | /** |
||
97 | * DOM object container needed for element creation with php's default DOM method |
||
98 | * |
||
99 | * @var \DOMDocument |
||
100 | */ |
||
101 | protected $_DOMDoc = null; |
||
102 | |||
103 | |||
104 | |||
105 | /** |
||
106 | * Magic overload: Proxy calls to the navigation container |
||
107 | * |
||
108 | * @param string $method method name in container |
||
109 | * @param array $arguments rguments to pass |
||
110 | * @return mixed |
||
111 | * @throws Navigation\Exception\ExceptionInterface |
||
112 | */ |
||
113 | public function __call($method, array $arguments = []) |
||
120 | |||
121 | /** |
||
122 | * Magic overload: Proxy to {@link render()}. |
||
123 | * |
||
124 | * This method will trigger an E_USER_ERROR if rendering the helper causes |
||
125 | * an exception to be thrown. |
||
126 | * |
||
127 | * Implements {@link HelperInterface::__toString()}. |
||
128 | * |
||
129 | * @return string |
||
130 | */ |
||
131 | public function __toString() |
||
135 | |||
136 | /** |
||
137 | * render component |
||
138 | * |
||
139 | * @param boolean $output |
||
140 | * |
||
141 | * @return string |
||
142 | */ |
||
143 | View Code Duplication | public function render($output = false) |
|
160 | |||
161 | /** |
||
162 | * Determines whether a page should be allowed given certain parameters |
||
163 | * |
||
164 | * @param array $params |
||
165 | * @return bool |
||
166 | */ |
||
167 | protected function isAllowed($params) |
||
172 | |||
173 | // Util methods: |
||
174 | |||
175 | /** |
||
176 | * Returns an HTML string containing an 'a' element for the given page |
||
177 | * |
||
178 | * @param AbstractPage $page page to generate HTML for |
||
179 | * @return string HTML string (<a href="…">Label</a>) |
||
180 | */ |
||
181 | public function htmlify(AbstractPage $page) |
||
201 | |||
202 | /** |
||
203 | * Normalize an ID |
||
204 | * |
||
205 | * Overrides {@link View\Helper\AbstractHtmlElement::normalizeId()}. |
||
206 | * |
||
207 | * @param string $value |
||
208 | * @return string |
||
209 | */ |
||
210 | protected function normalizeId($value) |
||
217 | |||
218 | // |
||
219 | // component related methods |
||
220 | // |
||
221 | |||
222 | /** |
||
223 | * @return string the assemled component rendered to HTML |
||
224 | */ |
||
225 | public function buildComponent() { |
||
247 | |||
248 | /** |
||
249 | * create the component markup |
||
250 | * |
||
251 | * @param string $tagname |
||
252 | * @param string $classnames |
||
253 | * @param array $attributes |
||
254 | * @param string|mixed $content |
||
255 | * |
||
256 | * @return string the component markup |
||
257 | */ |
||
258 | public function _createElement($tagname = 'div', $classnames = '', $attributes = array(), $content = '') { |
||
298 | |||
299 | |||
300 | // |
||
301 | // component related getters/setters |
||
302 | // |
||
303 | |||
304 | /** |
||
305 | * get main tag-name |
||
306 | * |
||
307 | * @return string the $tagname |
||
308 | */ |
||
309 | public function getTagname() { |
||
312 | |||
313 | /** |
||
314 | * set main tag-name |
||
315 | * |
||
316 | * @param string $tagname |
||
317 | */ |
||
318 | public function setTagname($tagname) { |
||
324 | |||
325 | /** |
||
326 | * get the element header |
||
327 | * |
||
328 | * @return mixed the $header |
||
329 | */ |
||
330 | public function getHeader() { |
||
333 | |||
334 | /** |
||
335 | * set the element header |
||
336 | * |
||
337 | * @param mixed $header |
||
338 | */ |
||
339 | public function setHeader($header) { |
||
345 | |||
346 | /** |
||
347 | * get the element footer |
||
348 | * |
||
349 | * @return mixed the $footer |
||
350 | */ |
||
351 | public function getFooter() { |
||
354 | |||
355 | /** |
||
356 | * set the element footer |
||
357 | * |
||
358 | * @param mixed $footer |
||
359 | */ |
||
360 | public function setFooter($footer = null) { |
||
366 | |||
367 | /** |
||
368 | * get the element content |
||
369 | * @return the $content |
||
370 | */ |
||
371 | public function getContent() { |
||
374 | |||
375 | /** |
||
376 | * set the element content |
||
377 | * |
||
378 | * @param string|array $content |
||
379 | */ |
||
380 | public function setContent($content = '') { |
||
384 | |||
385 | /** |
||
386 | * get DOM object |
||
387 | * |
||
388 | * @return the $_DOMDoc |
||
389 | */ |
||
390 | public function getDOMDoc() { |
||
396 | |||
397 | /** |
||
398 | * set DOM object |
||
399 | * |
||
400 | * @param \DOMDocument $_DOMDoc |
||
401 | */ |
||
402 | public function setDOMDoc(\DOMDocument $_DOMDoc) { |
||
406 | |||
407 | } |
||
408 |
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.