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 XmlDomParser 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 XmlDomParser, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class XmlDomParser extends AbstractDomParser |
||
17 | { |
||
18 | /** |
||
19 | * @param \DOMNode|SimpleXmlDomInterface|string $element HTML code or SimpleXmlDomInterface, \DOMNode |
||
20 | */ |
||
21 | 3 | View Code Duplication | public function __construct($element = null) |
49 | |||
50 | /** |
||
51 | * @param string $name |
||
52 | * @param array $arguments |
||
53 | * |
||
54 | * @throws \BadMethodCallException |
||
55 | * @throws \RuntimeException |
||
56 | * |
||
57 | * @return XmlDomParser |
||
58 | */ |
||
59 | 3 | View Code Duplication | public static function __callStatic($name, $arguments) |
79 | |||
80 | /** @noinspection MagicMethodsValidityInspection */ |
||
81 | |||
82 | /** |
||
83 | * @param string $name |
||
84 | * |
||
85 | * @return string|null |
||
86 | */ |
||
87 | public function __get($name) |
||
97 | |||
98 | /** |
||
99 | * @return string |
||
100 | */ |
||
101 | 2 | public function __toString() |
|
105 | |||
106 | /** |
||
107 | * Create DOMDocument from XML. |
||
108 | * |
||
109 | * @param string $xml |
||
110 | * @param int|null $libXMLExtraOptions |
||
111 | * |
||
112 | * @return \DOMDocument |
||
113 | */ |
||
114 | 3 | protected function createDOMDocument(string $xml, $libXMLExtraOptions = null): \DOMDocument |
|
186 | |||
187 | /** |
||
188 | * Find list of nodes with a CSS selector. |
||
189 | * |
||
190 | * @param string $selector |
||
191 | * @param int|null $idx |
||
192 | * |
||
193 | * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
194 | */ |
||
195 | 1 | View Code Duplication | public function find(string $selector, $idx = null) |
226 | |||
227 | /** |
||
228 | * Find nodes with a CSS selector. |
||
229 | * |
||
230 | * @param string $selector |
||
231 | * |
||
232 | * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
233 | */ |
||
234 | 1 | public function findMulti(string $selector): SimpleXmlDomNodeInterface |
|
238 | |||
239 | /** |
||
240 | * Find nodes with a CSS selector or false, if no element is found. |
||
241 | * |
||
242 | * @param string $selector |
||
243 | * |
||
244 | * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
245 | */ |
||
246 | 1 | public function findMultiOrFalse(string $selector) |
|
256 | |||
257 | /** |
||
258 | * Find one node with a CSS selector. |
||
259 | * |
||
260 | * @param string $selector |
||
261 | * |
||
262 | * @return SimpleXmlDomInterface |
||
263 | */ |
||
264 | 1 | public function findOne(string $selector): SimpleXmlDomInterface |
|
268 | |||
269 | /** |
||
270 | * Find one node with a CSS selector or false, if no element is found. |
||
271 | * |
||
272 | * @param string $selector |
||
273 | * |
||
274 | * @return false|SimpleXmlDomInterface |
||
275 | */ |
||
276 | 1 | public function findOneOrFalse(string $selector) |
|
286 | |||
287 | /** |
||
288 | * @param string $content |
||
289 | * @param bool $multiDecodeNewHtmlEntity |
||
290 | * |
||
291 | * @return string |
||
292 | */ |
||
293 | public function fixHtmlOutput(string $content, bool $multiDecodeNewHtmlEntity = false): string |
||
299 | |||
300 | /** |
||
301 | * Return elements by ".class". |
||
302 | * |
||
303 | * @param string $class |
||
304 | * |
||
305 | * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
306 | */ |
||
307 | public function getElementByClass(string $class): SimpleXmlDomNodeInterface |
||
311 | |||
312 | /** |
||
313 | * Return element by #id. |
||
314 | * |
||
315 | * @param string $id |
||
316 | * |
||
317 | * @return SimpleXmlDomInterface |
||
318 | */ |
||
319 | public function getElementById(string $id): SimpleXmlDomInterface |
||
323 | |||
324 | /** |
||
325 | * Return element by tag name. |
||
326 | * |
||
327 | * @param string $name |
||
328 | * |
||
329 | * @return SimpleXmlDomInterface |
||
330 | */ |
||
331 | public function getElementByTagName(string $name): SimpleXmlDomInterface |
||
341 | |||
342 | /** |
||
343 | * Returns elements by "#id". |
||
344 | * |
||
345 | * @param string $id |
||
346 | * @param int|null $idx |
||
347 | * |
||
348 | * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
349 | */ |
||
350 | public function getElementsById(string $id, $idx = null) |
||
354 | |||
355 | /** |
||
356 | * Returns elements by tag name. |
||
357 | * |
||
358 | * @param string $name |
||
359 | * @param int|null $idx |
||
360 | * |
||
361 | * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
362 | */ |
||
363 | View Code Duplication | public function getElementsByTagName(string $name, $idx = null) |
|
390 | |||
391 | /** |
||
392 | * Get dom node's outer html. |
||
393 | * |
||
394 | * @param bool $multiDecodeNewHtmlEntity |
||
395 | * |
||
396 | * @return string |
||
397 | */ |
||
398 | public function html(bool $multiDecodeNewHtmlEntity = false): string |
||
412 | |||
413 | /** |
||
414 | * Load HTML from string. |
||
415 | * |
||
416 | * @param string $html |
||
417 | * @param int|null $libXMLExtraOptions |
||
418 | * |
||
419 | * @return self |
||
420 | */ |
||
421 | public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface |
||
427 | |||
428 | /** |
||
429 | * Load HTML from file. |
||
430 | * |
||
431 | * @param string $filePath |
||
432 | * @param int|null $libXMLExtraOptions |
||
433 | * |
||
434 | * @throws \RuntimeException |
||
435 | * |
||
436 | * @return XmlDomParser |
||
437 | */ |
||
438 | View Code Duplication | public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface |
|
465 | |||
466 | /** |
||
467 | * @param string $selector |
||
468 | * @param int $idx |
||
469 | * |
||
470 | * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface> |
||
471 | */ |
||
472 | public function __invoke($selector, $idx = null) |
||
476 | |||
477 | /** |
||
478 | * Load XML from string. |
||
479 | * |
||
480 | * @param string $xml |
||
481 | * @param int|null $libXMLExtraOptions |
||
482 | * |
||
483 | * @return XmlDomParser |
||
484 | */ |
||
485 | 3 | public function loadXml(string $xml, $libXMLExtraOptions = null): self |
|
491 | |||
492 | /** |
||
493 | * Load XML from file. |
||
494 | * |
||
495 | * @param string $filePath |
||
496 | * @param int|null $libXMLExtraOptions |
||
497 | * |
||
498 | * @throws \RuntimeException |
||
499 | * |
||
500 | * @return XmlDomParser |
||
501 | */ |
||
502 | 2 | View Code Duplication | public function loadXmlFile(string $filePath, $libXMLExtraOptions = null): self |
529 | |||
530 | /** |
||
531 | * @param callable $callback |
||
532 | * @param \DOMNode|null $domNode |
||
533 | * |
||
534 | * @return void |
||
535 | */ |
||
536 | 1 | public function replaceTextWithCallback($callback, \DOMNode $domNode = null) |
|
568 | } |
||
569 |
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.