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 |
||
35 | class BindingDescriptor |
||
36 | { |
||
37 | /** |
||
38 | * @var Binding |
||
39 | */ |
||
40 | private $binding; |
||
41 | |||
42 | /** |
||
43 | * @var int |
||
44 | */ |
||
45 | private $state; |
||
46 | |||
47 | /** |
||
48 | * @var Module |
||
49 | */ |
||
50 | private $containingModule; |
||
51 | |||
52 | /** |
||
53 | * @var BindingTypeDescriptor |
||
54 | */ |
||
55 | private $typeDescriptor; |
||
56 | |||
57 | /** |
||
58 | * @var Exception[] |
||
59 | */ |
||
60 | private $loadErrors; |
||
61 | |||
62 | /** |
||
63 | * Creates a new binding descriptor. |
||
64 | * |
||
65 | * @param Binding $binding The described binding. |
||
66 | */ |
||
67 | 116 | public function __construct(Binding $binding) |
|
68 | { |
||
69 | 116 | $this->binding = $binding; |
|
70 | 116 | } |
|
71 | |||
72 | /** |
||
73 | * Loads the binding descriptor. |
||
74 | * |
||
75 | * @param Module $containingModule The module that |
||
76 | * contains the |
||
77 | * descriptor. |
||
78 | * @param BindingTypeDescriptor|null $typeDescriptor The type descriptor. |
||
79 | * |
||
80 | * @throws AlreadyLoadedException If the descriptor is already loaded. |
||
81 | */ |
||
82 | 64 | public function load(Module $containingModule, BindingTypeDescriptor $typeDescriptor = null) |
|
83 | { |
||
84 | 64 | if (null !== $this->state) { |
|
85 | throw new AlreadyLoadedException('The binding descriptor is already loaded.'); |
||
86 | } |
||
87 | |||
88 | 64 | $this->loadErrors = array(); |
|
89 | |||
90 | 64 | if ($typeDescriptor && $typeDescriptor->isLoaded() && $typeDescriptor->isEnabled()) { |
|
91 | try { |
||
92 | 49 | $this->binding->initialize($typeDescriptor->getType()); |
|
93 | 6 | } catch (Exception $e) { |
|
94 | 6 | $this->loadErrors[] = $e; |
|
95 | } |
||
96 | } |
||
97 | |||
98 | 64 | $this->containingModule = $containingModule; |
|
99 | 64 | $this->typeDescriptor = $typeDescriptor; |
|
100 | |||
101 | 64 | $this->refreshState(); |
|
102 | 64 | } |
|
103 | |||
104 | /** |
||
105 | * Unloads the binding descriptor. |
||
106 | * |
||
107 | * All memory allocated during {@link load()} is freed. |
||
108 | * |
||
109 | * @throws NotLoadedException If the descriptor is not loaded. |
||
110 | */ |
||
111 | 20 | public function unload() |
|
112 | { |
||
113 | 20 | if (null === $this->state) { |
|
114 | throw new NotLoadedException('The binding descriptor is not loaded.'); |
||
115 | } |
||
116 | |||
117 | 20 | $this->containingModule = null; |
|
118 | 20 | $this->typeDescriptor = null; |
|
119 | 20 | $this->loadErrors = array(); |
|
120 | 20 | $this->state = null; |
|
121 | 20 | } |
|
122 | |||
123 | /** |
||
124 | * Returns whether the descriptor is loaded. |
||
125 | * |
||
126 | * @return bool Returns `true` if the descriptor is loaded. |
||
127 | */ |
||
128 | 52 | public function isLoaded() |
|
132 | |||
133 | /** |
||
134 | * Returns the UUID of the described binding. |
||
135 | * |
||
136 | * @return Uuid The UUID. |
||
137 | */ |
||
138 | 67 | public function getUuid() |
|
139 | { |
||
140 | 67 | return $this->binding->getUuid(); |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * Returns the name of the bound type. |
||
145 | * |
||
146 | * @return string The type name. |
||
147 | */ |
||
148 | 62 | public function getTypeName() |
|
152 | |||
153 | /** |
||
154 | * Returns the described binding. |
||
155 | * |
||
156 | * @return Binding The binding. |
||
157 | */ |
||
158 | 31 | public function getBinding() |
|
162 | |||
163 | /** |
||
164 | * Returns the errors that happened during loading. |
||
165 | * |
||
166 | * The method {@link load()} needs to be called before calling this method, |
||
167 | * otherwise an exception is thrown. |
||
168 | * |
||
169 | * @return Exception[] The load errors. |
||
170 | * |
||
171 | * @throws NotLoadedException If the descriptor is not loaded. |
||
172 | */ |
||
173 | 11 | public function getLoadErrors() |
|
181 | |||
182 | /** |
||
183 | * Returns the module that contains the descriptor. |
||
184 | * |
||
185 | * The method {@link load()} needs to be called before calling this method, |
||
186 | * otherwise an exception is thrown. |
||
187 | * |
||
188 | * @return Module The containing module. |
||
189 | * |
||
190 | * @throws NotLoadedException If the descriptor is not loaded. |
||
191 | */ |
||
192 | 38 | public function getContainingModule() |
|
193 | { |
||
194 | 38 | if (null === $this->containingModule) { |
|
195 | throw new NotLoadedException('The binding descriptor is not loaded.'); |
||
196 | } |
||
197 | |||
198 | 38 | return $this->containingModule; |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * Returns the type descriptor. |
||
203 | * |
||
204 | * The method {@link load()} needs to be called before calling this method, |
||
205 | * otherwise an exception is thrown. |
||
206 | * |
||
207 | * @return BindingTypeDescriptor|null The type descriptor or null, if no |
||
208 | * type descriptor exists for the |
||
209 | * binding's type name. |
||
210 | * |
||
211 | * @throws NotLoadedException If the binding descriptor is not loaded. |
||
212 | */ |
||
213 | 7 | public function getTypeDescriptor() |
|
214 | { |
||
215 | // Check containing module, as the type descriptor may be null |
||
216 | 7 | if (null === $this->containingModule) { |
|
217 | throw new NotLoadedException('The binding descriptor is not loaded.'); |
||
218 | } |
||
219 | |||
220 | 7 | return $this->typeDescriptor; |
|
221 | } |
||
222 | |||
223 | /** |
||
224 | * Returns the state of the binding. |
||
225 | * |
||
226 | * The method {@link load()} needs to be called before calling this method, |
||
227 | * otherwise an exception is thrown. |
||
228 | * |
||
229 | * @return int One of the {@link BindingState} constants. |
||
230 | * |
||
231 | * @throws NotLoadedException If the descriptor is not loaded. |
||
232 | */ |
||
233 | 8 | public function getState() |
|
234 | { |
||
235 | 8 | if (null === $this->state) { |
|
236 | throw new NotLoadedException('The binding descriptor is not loaded.'); |
||
237 | } |
||
238 | |||
239 | 8 | return $this->state; |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * Returns whether the binding is enabled. |
||
244 | * |
||
245 | * The method {@link load()} needs to be called before calling this method, |
||
246 | * otherwise an exception is thrown. |
||
247 | * |
||
248 | * @return bool Returns `true` if the state is {@link BindingState::ENABLED}. |
||
249 | * |
||
250 | * @throws NotLoadedException If the descriptor is not loaded. |
||
251 | * |
||
252 | * @see BindingState::ENABLED |
||
253 | */ |
||
254 | 32 | View Code Duplication | public function isEnabled() |
262 | |||
263 | /** |
||
264 | * Returns whether the binding is disabled. |
||
265 | * |
||
266 | * The method {@link load()} needs to be called before calling this method, |
||
267 | * otherwise an exception is thrown. |
||
268 | * |
||
269 | * @return bool Returns `true` if the state is {@link BindingState::DISABLED}. |
||
270 | * |
||
271 | * @throws NotLoadedException If the descriptor is not loaded. |
||
272 | * |
||
273 | * @see BindingState::DISABLED |
||
274 | */ |
||
275 | 4 | View Code Duplication | public function isDisabled() |
283 | |||
284 | /** |
||
285 | * Returns whether the type of the binding does not exist. |
||
286 | * |
||
287 | * The method {@link load()} needs to be called before calling this method, |
||
288 | * otherwise an exception is thrown. |
||
289 | * |
||
290 | * @return bool Returns `true` if the state is {@link BindingState::TYPE_NOT_FOUND}. |
||
291 | * |
||
292 | * @throws NotLoadedException If the descriptor is not loaded. |
||
293 | * |
||
294 | * @see BindingState::TYPE_NOT_FOUND |
||
295 | */ |
||
296 | 19 | View Code Duplication | public function isTypeNotFound() |
304 | |||
305 | /** |
||
306 | * Returns whether the type of the binding is not enabled. |
||
307 | * |
||
308 | * The method {@link load()} needs to be called before calling this method, |
||
309 | * otherwise an exception is thrown. |
||
310 | * |
||
311 | * @return bool Returns `true` if the state is {@link BindingState::TYPE_NOT_ENABLED}. |
||
312 | * |
||
313 | * @throws NotLoadedException If the descriptor is not loaded. |
||
314 | * |
||
315 | * @see BindingState::TYPE_NOT_ENABLED |
||
316 | */ |
||
317 | 15 | View Code Duplication | public function isTypeNotEnabled() |
325 | |||
326 | /** |
||
327 | * Returns whether the binding is invalid. |
||
328 | * |
||
329 | * The method {@link load()} needs to be called before calling this method, |
||
330 | * otherwise an exception is thrown. |
||
331 | * |
||
332 | * @return bool Returns `true` if the state is {@link BindingState::INVALID}. |
||
333 | * |
||
334 | * @throws NotLoadedException If the descriptor is not loaded. |
||
335 | * |
||
336 | * @see BindingState::INVALID |
||
337 | */ |
||
338 | View Code Duplication | public function isInvalid() |
|
346 | |||
347 | 64 | private function refreshState() |
|
348 | { |
||
349 | 64 | if (null === $this->typeDescriptor || !$this->typeDescriptor->isLoaded()) { |
|
363 | } |
||
364 |
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.