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 Filesystem 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 Filesystem, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class Filesystem implements FilesystemInterface |
||
20 | { |
||
21 | /** |
||
22 | * @var array |
||
23 | */ |
||
24 | protected $plugins = array(); |
||
25 | |||
26 | /** |
||
27 | * Register a plugin. |
||
28 | * |
||
29 | * @param PluginInterface $plugin |
||
30 | * |
||
31 | * @return $this |
||
32 | */ |
||
33 | 9 | public function addPlugin(PluginInterface $plugin) |
|
39 | |||
40 | /** |
||
41 | * Find a specific plugin. |
||
42 | * |
||
43 | * @param string $method |
||
44 | * |
||
45 | * @throws LogicException |
||
46 | * |
||
47 | * @return PluginInterface $plugin |
||
48 | */ |
||
49 | 15 | View Code Duplication | protected function findPlugin($method) |
61 | |||
62 | /** |
||
63 | * Invoke a plugin by method name. |
||
64 | * |
||
65 | * @param string $method |
||
66 | * @param array $arguments |
||
67 | * |
||
68 | * @return mixed |
||
69 | */ |
||
70 | 15 | View Code Duplication | protected function invokePlugin($method, array $arguments, FilesystemInterface $filesystem) |
78 | |||
79 | /** |
||
80 | * Plugins pass-through. |
||
81 | * |
||
82 | * @param string $method |
||
83 | * @param array $arguments |
||
84 | * |
||
85 | * @throws BadMethodCallException |
||
86 | * |
||
87 | * @return mixed |
||
88 | */ |
||
89 | 15 | View Code Duplication | public function __call($method, array $arguments) |
101 | |||
102 | |||
103 | |||
104 | /** |
||
105 | * @var Config |
||
106 | */ |
||
107 | protected $config; |
||
108 | |||
109 | /** |
||
110 | * Set the config. |
||
111 | * |
||
112 | * @param Config|array|null $config |
||
113 | */ |
||
114 | 228 | protected function setConfig($config) |
|
118 | |||
119 | /** |
||
120 | * Get the Config. |
||
121 | * |
||
122 | * @return Config config object |
||
123 | */ |
||
124 | 57 | public function getConfig() |
|
132 | |||
133 | /** |
||
134 | * Convert a config array to a Config object with the correct fallback. |
||
135 | * |
||
136 | * @param array $config |
||
137 | * |
||
138 | * @return Config |
||
139 | */ |
||
140 | 54 | protected function prepareConfig(array $config) |
|
147 | |||
148 | /** |
||
149 | * @var AdapterInterface |
||
150 | */ |
||
151 | protected $adapter; |
||
152 | |||
153 | /** |
||
154 | * Constructor. |
||
155 | * |
||
156 | * @param AdapterInterface $adapter |
||
157 | * @param Config|array $config |
||
158 | */ |
||
159 | 228 | public function __construct(AdapterInterface $adapter, $config = null) |
|
164 | |||
165 | /** |
||
166 | * Get the Adapter. |
||
167 | * |
||
168 | * @return AdapterInterface adapter |
||
169 | */ |
||
170 | 192 | public function getAdapter() |
|
174 | |||
175 | /** |
||
176 | * @inheritdoc |
||
177 | */ |
||
178 | 159 | public function has($path) |
|
184 | |||
185 | /** |
||
186 | * @inheritdoc |
||
187 | */ |
||
188 | 12 | View Code Duplication | public function write($path, $contents, array $config = array()) |
196 | |||
197 | /** |
||
198 | * @inheritdoc |
||
199 | */ |
||
200 | 15 | View Code Duplication | public function writeStream($path, $resource, array $config = array()) |
214 | |||
215 | /** |
||
216 | * @inheritdoc |
||
217 | */ |
||
218 | 9 | public function put($path, $contents, array $config = array()) |
|
229 | |||
230 | /** |
||
231 | * @inheritdoc |
||
232 | */ |
||
233 | 12 | public function putStream($path, $resource, array $config = array()) |
|
249 | |||
250 | /** |
||
251 | * @inheritdoc |
||
252 | */ |
||
253 | 6 | public function readAndDelete($path) |
|
267 | |||
268 | /** |
||
269 | * @inheritdoc |
||
270 | */ |
||
271 | 6 | View Code Duplication | public function update($path, $contents, array $config = array()) |
280 | |||
281 | /** |
||
282 | * @inheritdoc |
||
283 | */ |
||
284 | 15 | View Code Duplication | public function updateStream($path, $resource, array $config = array()) |
297 | |||
298 | /** |
||
299 | * @inheritdoc |
||
300 | */ |
||
301 | 36 | public function read($path) |
|
312 | |||
313 | /** |
||
314 | * @inheritdoc |
||
315 | */ |
||
316 | 12 | public function readStream($path) |
|
327 | |||
328 | /** |
||
329 | * @inheritdoc |
||
330 | */ |
||
331 | 9 | View Code Duplication | public function rename($path, $newpath) |
340 | |||
341 | /** |
||
342 | * @inheritdoc |
||
343 | */ |
||
344 | 9 | View Code Duplication | public function copy($path, $newpath) |
353 | |||
354 | /** |
||
355 | * @inheritdoc |
||
356 | */ |
||
357 | 60 | public function delete($path) |
|
364 | |||
365 | /** |
||
366 | * @inheritdoc |
||
367 | */ |
||
368 | 63 | public function deleteDir($dirname) |
|
378 | |||
379 | /** |
||
380 | * @inheritdoc |
||
381 | */ |
||
382 | 3 | View Code Duplication | public function createDir($dirname, array $config = array()) |
389 | |||
390 | /** |
||
391 | * @inheritdoc |
||
392 | */ |
||
393 | 12 | public function listContents($directory = '', $recursive = false) |
|
400 | |||
401 | /** |
||
402 | * @inheritdoc |
||
403 | */ |
||
404 | 9 | public function getMimetype($path) |
|
415 | |||
416 | /** |
||
417 | * @inheritdoc |
||
418 | */ |
||
419 | 9 | public function getTimestamp($path) |
|
430 | |||
431 | /** |
||
432 | * @inheritdoc |
||
433 | */ |
||
434 | 9 | View Code Duplication | public function getVisibility($path) |
445 | |||
446 | /** |
||
447 | * @inheritdoc |
||
448 | */ |
||
449 | 9 | View Code Duplication | public function getSize($path) |
459 | |||
460 | /** |
||
461 | * @inheritdoc |
||
462 | */ |
||
463 | 6 | public function setVisibility($path, $visibility) |
|
469 | |||
470 | /** |
||
471 | * @inheritdoc |
||
472 | */ |
||
473 | 51 | public function getMetadata($path) |
|
480 | |||
481 | /** |
||
482 | * @inheritdoc |
||
483 | */ |
||
484 | 69 | public function get($path, Handler $handler = null) |
|
498 | |||
499 | /** |
||
500 | * Assert a file is present. |
||
501 | * |
||
502 | * @param string $path path to file |
||
503 | * |
||
504 | * @throws FileNotFoundException |
||
505 | */ |
||
506 | 126 | public function assertPresent($path) |
|
512 | |||
513 | /** |
||
514 | * Assert a file is absent. |
||
515 | * |
||
516 | * @param string $path path to file |
||
517 | * |
||
518 | * @throws FileExistsException |
||
519 | */ |
||
520 | 39 | public function assertAbsent($path) |
|
526 | } |
||
527 |
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.