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:
1 | <?php |
||
37 | class ConfigValueHolder implements \ArrayAccess, \IteratorAggregate |
||
38 | { |
||
39 | /** |
||
40 | * @var string The name of this value. |
||
41 | */ |
||
42 | protected $_name = ''; |
||
43 | /** |
||
44 | * @var array The attributes of this value. |
||
45 | */ |
||
46 | protected $_attributes = array(); |
||
47 | /** |
||
48 | * @var array The child nodes of this value. |
||
49 | */ |
||
50 | protected $_childs = array(); |
||
51 | /** |
||
52 | * @var string The value. |
||
53 | */ |
||
54 | protected $_value = null; |
||
55 | |||
56 | /** |
||
57 | * Sets the name of this value. |
||
58 | * |
||
59 | * @param string $name The name. |
||
60 | * |
||
61 | * @author Dominik del Bondio <[email protected]> |
||
62 | * @since 0.11.0 |
||
63 | */ |
||
64 | public function setName($name) |
||
65 | { |
||
66 | $this->_name = $name; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Returns the name of this value. |
||
71 | * |
||
72 | * @return string The name. |
||
73 | * |
||
74 | * @author Dominik del Bondio <[email protected]> |
||
75 | * @since 0.11.0 |
||
76 | */ |
||
77 | public function getName() |
||
78 | { |
||
79 | return $this->_name; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * isset() overload. |
||
84 | * |
||
85 | * @param string $name Name of the child. |
||
86 | * |
||
87 | * @return bool Whether or not that child exists. |
||
88 | * |
||
89 | * @author Dominik del Bondio <[email protected]> |
||
90 | * @since 0.11.0 |
||
91 | */ |
||
92 | public function __isset($name) |
||
93 | { |
||
94 | return $this->hasChildren($name); |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Magic getter overload. |
||
99 | * |
||
100 | * @param string $name Name of the child . |
||
101 | * |
||
102 | * @return ConfigValueHolder The child, if it exists. |
||
103 | * |
||
104 | * @author Dominik del Bondio <[email protected]> |
||
105 | * @since 0.11.0 |
||
106 | */ |
||
107 | public function __get($name) |
||
108 | { |
||
109 | if (isset($this->_childs[$name])) { |
||
110 | return $this->_childs[$name]; |
||
111 | } else { |
||
112 | $tagName = $name; |
||
113 | $tagNameStart = ''; |
||
114 | View Code Duplication | if (($lastUScore = strrpos($tagName, '_')) !== false) { |
|
|
|||
115 | $lastUScore++; |
||
116 | $tagNameStart = substr($tagName, 0, $lastUScore); |
||
117 | $tagName = substr($tagName, $lastUScore); |
||
118 | } |
||
119 | |||
120 | // check if the requested node was specified using the plural version |
||
121 | // and create a "virtual" node which reflects the non existent plural node |
||
122 | $singularName = $tagNameStart . Inflector::singularize($tagName); |
||
123 | if ($this->hasChildren($singularName)) { |
||
124 | $vh = new ConfigValueHolder(); |
||
125 | $vh->setName($name); |
||
126 | |||
127 | /** @var ConfigValueHolder $child */ |
||
128 | foreach ($this->_childs as $child) { |
||
129 | if ($child->getName() == $singularName) { |
||
130 | $vh->addChildren($singularName, $child); |
||
131 | } |
||
132 | } |
||
133 | |||
134 | return $vh; |
||
135 | } else { |
||
136 | //throw new AgaviException('Node with the name ' . $name . ' does not exist ('.$this->getName().', '.implode(', ', array_keys($this->_childs)).')'); |
||
137 | return null; |
||
138 | } |
||
139 | } |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Adds a named children to this value. If a children with the same name |
||
144 | * already exists the given value will be appended to the children. |
||
145 | * |
||
146 | * @param string $name The name of the child. |
||
147 | * @param ConfigValueHolder $children The child value. |
||
148 | * |
||
149 | * @author Dominik del Bondio <[email protected]> |
||
150 | * @since 0.11.0 |
||
151 | */ |
||
152 | public function addChildren($name, $children) |
||
161 | |||
162 | /** |
||
163 | * Adds a unnamed children to this value. |
||
164 | * |
||
165 | * @param ConfigValueHolder $children The child value. |
||
166 | * |
||
167 | * @author Dominik del Bondio <[email protected]> |
||
168 | * @since 0.11.0 |
||
169 | */ |
||
170 | public function appendChildren($children) |
||
174 | |||
175 | /** |
||
176 | * Checks whether the value has children at all (no params) or whether a |
||
177 | * child with the given name exists. |
||
178 | * |
||
179 | * @param string $child The name of the child. |
||
180 | * |
||
181 | * @return bool True if children exist, false if not. |
||
182 | * |
||
183 | * @author Dominik del Bondio <[email protected]> |
||
184 | * @since 0.11.0 |
||
185 | */ |
||
186 | public function hasChildren($child = null) |
||
207 | |||
208 | /** |
||
209 | * Returns the children of this value. |
||
210 | * |
||
211 | * @param string $nodename Return only the childs matching this node (tag) name. |
||
212 | * |
||
213 | * @return ConfigValueHolder[] An array with the childs of this value. |
||
214 | * |
||
215 | * @author Dominik del Bondio <[email protected]> |
||
216 | * @since 0.11.0 |
||
217 | */ |
||
218 | public function getChildren($nodename = null) |
||
234 | |||
235 | /** |
||
236 | * Set an attribute. |
||
237 | * |
||
238 | * If an attribute with the name already exists the value will be |
||
239 | * overridden. |
||
240 | * |
||
241 | * @param string $name An attribute name. |
||
242 | * @param mixed $value An attribute value. |
||
243 | * |
||
244 | * @author Dominik del Bondio <[email protected]> |
||
245 | * @since 0.11.0 |
||
246 | */ |
||
247 | public function setAttribute($name, $value) |
||
251 | |||
252 | /** |
||
253 | * Indicates whether or not an attribute exists. |
||
254 | * |
||
255 | * @param string $name An attribute name. |
||
256 | * |
||
257 | * @return bool true, if the attribute exists, otherwise false. |
||
258 | * |
||
259 | * @author Dominik del Bondio <[email protected]> |
||
260 | * @since 0.11.0 |
||
261 | */ |
||
262 | public function hasAttribute($name) |
||
266 | |||
267 | /** |
||
268 | * Retrieve an attribute. |
||
269 | * |
||
270 | * @param string $name An attribute name. |
||
271 | * @param mixed $default A default attribute value. |
||
272 | * |
||
273 | * @return mixed An attribute value, if the attribute exists, otherwise |
||
274 | * null or the given default. |
||
275 | * |
||
276 | * @author Dominik del Bondio <[email protected]> |
||
277 | * @since 0.11.0 |
||
278 | */ |
||
279 | public function getAttribute($name, $default = null) |
||
283 | |||
284 | /** |
||
285 | * Retrieve all attributes. |
||
286 | * |
||
287 | * @return array An associative array of attributes. |
||
288 | * |
||
289 | * @author Dominik del Bondio <[email protected]> |
||
290 | * @since 0.11.0 |
||
291 | */ |
||
292 | public function getAttributes() |
||
296 | |||
297 | /** |
||
298 | * Set the value of this value node. |
||
299 | * |
||
300 | * @param string $value A value. |
||
301 | * |
||
302 | * @author Dominik del Bondio <[email protected]> |
||
303 | * @since 0.11.0 |
||
304 | */ |
||
305 | public function setValue($value) |
||
309 | |||
310 | /** |
||
311 | * Retrieves the value of this value node. |
||
312 | * |
||
313 | * @return string The value of this node. |
||
314 | * |
||
315 | * @author Dominik del Bondio <[email protected]> |
||
316 | * @since 0.11.0 |
||
317 | */ |
||
318 | public function getValue() |
||
322 | |||
323 | /** |
||
324 | * Retrieves the info of this value node. |
||
325 | * |
||
326 | * @return array An array containing the info for this node. |
||
327 | * |
||
328 | * @author Dominik del Bondio <[email protected]> |
||
329 | * @since 0.11.0 |
||
330 | */ |
||
331 | public function getNode() |
||
340 | |||
341 | /** |
||
342 | * Determines if a named child exists. From ArrayAccess. |
||
343 | * |
||
344 | * @param string $offset Offset to check |
||
345 | * |
||
346 | * @return bool Whether the offset exists. |
||
347 | * |
||
348 | * @author Dominik del Bondio <[email protected]> |
||
349 | * @since 0.11.0 |
||
350 | */ |
||
351 | public function offsetExists($offset) |
||
355 | |||
356 | /** |
||
357 | * Retrieves a named child. From ArrayAccess. |
||
358 | * |
||
359 | * @param string $offset Offset to retrieve |
||
360 | * |
||
361 | * @return ConfigValueHolder The child value. |
||
362 | * |
||
363 | * @author Dominik del Bondio <[email protected]> |
||
364 | * @since 0.11.0 |
||
365 | */ |
||
366 | public function offsetGet($offset) |
||
373 | |||
374 | /** |
||
375 | * Inserts a named child. From ArrayAccess. |
||
376 | * |
||
377 | * @param string $offset Offset to modify |
||
378 | * @param ConfigValueHolder $value The child value. |
||
379 | * |
||
380 | * @author Dominik del Bondio <[email protected]> |
||
381 | * @since 0.11.0 |
||
382 | */ |
||
383 | public function offsetSet($offset, $value) |
||
387 | |||
388 | /** |
||
389 | * Deletes a named child. From ArrayAccess. |
||
390 | * |
||
391 | * @return string $offset Offset to delete. |
||
392 | * |
||
393 | * @author Dominik del Bondio <[email protected]> |
||
394 | * @since 0.11.0 |
||
395 | */ |
||
396 | public function offsetUnset($offset) |
||
400 | |||
401 | /** |
||
402 | * Returns an Iterator for the child nodes. From IteratorAggregate. |
||
403 | * |
||
404 | * @return \Iterator The iterator. |
||
405 | * |
||
406 | * @author Dominik del Bondio <[email protected]> |
||
407 | * @since 0.11.0 |
||
408 | */ |
||
409 | public function getIterator() |
||
413 | |||
414 | /** |
||
415 | * Retrieves the string representation of this value node. This is |
||
416 | * currently only the value of the node. |
||
417 | * |
||
418 | * @return string The string representation. |
||
419 | * |
||
420 | * @author Dominik del Bondio <[email protected]> |
||
421 | * @since 0.11.0 |
||
422 | */ |
||
423 | public function __toString() |
||
427 | } |
||
428 |
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.