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 |
||
18 | class Lazy implements Loadable { |
||
19 | |||
20 | private $_list = []; |
||
21 | |||
22 | 15 | public function __construct(array $loaders = []) { |
|
23 | 15 | foreach ($loaders as $contentType => $loader) { |
|
24 | 10 | $this->add($contentType, $loader); |
|
25 | } |
||
26 | 14 | } |
|
27 | |||
28 | /** |
||
29 | * Add a loader to the list |
||
30 | * |
||
31 | * @param string $contentType |
||
32 | * @param Loadable|callable $loader |
||
33 | * @throws \UnexpectedValueException |
||
34 | */ |
||
35 | 14 | public function add(string $contentType, $loader) { |
|
36 | 14 | $contentType = $this->normalizeContentType($contentType); |
|
37 | 14 | if ($loader instanceof Loadable || is_callable($loader)) { |
|
38 | 13 | $this->_list[$contentType] = $loader; |
|
39 | 13 | return; |
|
40 | } |
||
41 | 1 | throw new \UnexpectedValueException( |
|
42 | 1 | sprintf( |
|
43 | 1 | 'Lazy loader for content type "%s" is not a callable or FluentDOM\Loadable', |
|
44 | 1 | $contentType |
|
45 | ) |
||
46 | ); |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Add loader classes for different types |
||
51 | * |
||
52 | * @param array[] $classes ['class' => ['type/one', 'type/two'], ...] |
||
53 | * @param string $namespace |
||
54 | * @throws \LogicException |
||
55 | * @throws \UnexpectedValueException |
||
56 | */ |
||
57 | 4 | public function addClasses($classes, string $namespace = '') { |
|
58 | 4 | foreach ($classes as $loader => $types) { |
|
59 | 4 | $class = str_replace(['\\\\\\', '\\\\'], '\\', $namespace.'\\'.$loader); |
|
60 | 4 | $callback = function() use ($class) { |
|
61 | 3 | if (!class_exists($class)) { |
|
62 | 1 | throw new \LogicException( |
|
63 | 1 | sprintf( |
|
64 | 1 | 'Loader class "%s" not found.', $class |
|
65 | ) |
||
66 | ); |
||
67 | } |
||
68 | 2 | return new $class; |
|
69 | 4 | }; |
|
70 | 4 | if (is_array($types)) { |
|
71 | 2 | foreach ($types as $type) { |
|
72 | 2 | $this->add($type, $callback); |
|
73 | } |
||
74 | } else { |
||
75 | 2 | $this->add((string)$types, $callback); |
|
76 | } |
||
77 | } |
||
78 | 4 | } |
|
79 | |||
80 | /** |
||
81 | * @throws \UnexpectedValueException |
||
82 | * @param string $contentType |
||
83 | * @return bool|Loadable |
||
84 | */ |
||
85 | 10 | public function get(string $contentType) { |
|
86 | 10 | $contentType = $this->normalizeContentType($contentType); |
|
87 | 10 | if (isset($this->_list[$contentType])) { |
|
88 | 8 | if (!($this->_list[$contentType] instanceof Loadable)) { |
|
89 | 7 | $this->_list[$contentType] = call_user_func($this->_list[$contentType]); |
|
90 | } |
||
91 | 7 | if (!($this->_list[$contentType] instanceof Loadable)) { |
|
92 | 1 | unset($this->_list[$contentType]); |
|
93 | 1 | throw new \UnexpectedValueException( |
|
94 | 1 | sprintf( |
|
95 | 1 | 'Lazy loader for content type "%s" did not return a FluentDOM\Loadable', |
|
96 | 1 | $contentType |
|
97 | ) |
||
98 | ); |
||
99 | } |
||
100 | 6 | return $this->_list[$contentType]; |
|
101 | } |
||
102 | 2 | return FALSE; |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * @param string $contentType |
||
107 | * @return bool |
||
108 | */ |
||
109 | 3 | public function supports(string $contentType): bool { |
|
113 | |||
114 | /** |
||
115 | * @param mixed $source |
||
116 | * @param mixed $contentType |
||
117 | * @param array|\Traversable|Options $options |
||
118 | * @return Document|Result|NULL |
||
119 | */ |
||
120 | 2 | View Code Duplication | public function load($source, string $contentType, $options = []) { |
127 | |||
128 | /** |
||
129 | * @param mixed $source |
||
130 | * @param string $contentType |
||
131 | * @param array|\Traversable|Options $options |
||
132 | * @return DocumentFragment|NULL |
||
133 | * @throws \UnexpectedValueException |
||
134 | */ |
||
135 | 2 | View Code Duplication | public function loadFragment($source, string $contentType, $options = []) { |
142 | |||
143 | /** |
||
144 | * @param string $contentType |
||
145 | * @return string |
||
146 | */ |
||
147 | 15 | private function normalizeContentType(string $contentType): string { |
|
150 | } |
||
151 | } |