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 ImagemagickImage 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 ImagemagickImage, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class ImagemagickImage extends AbstractImage |
||
18 | { |
||
19 | /** |
||
20 | * The temporary file location |
||
21 | * @var string $tmpFile |
||
22 | */ |
||
23 | private $tmpFile; |
||
24 | |||
25 | /** |
||
26 | * @var string $mogrifyCmd |
||
27 | */ |
||
28 | private $mogrifyCmd; |
||
29 | |||
30 | /** |
||
31 | * @var string $convertCmd |
||
32 | */ |
||
33 | private $convertCmd; |
||
34 | |||
35 | /** |
||
36 | * @var string $compositeCmd |
||
37 | */ |
||
38 | private $compositeCmd; |
||
39 | |||
40 | /** |
||
41 | * @var string $identifyCmd |
||
42 | */ |
||
43 | private $identifyCmd; |
||
44 | |||
45 | /** |
||
46 | * Set up the commands. |
||
47 | */ |
||
48 | public function __construct() |
||
54 | |||
55 | /** |
||
56 | * Clean up the tmp file, if necessary |
||
57 | */ |
||
58 | public function __destruct() |
||
62 | |||
63 | /** |
||
64 | * @return string |
||
65 | */ |
||
66 | public function driverType() |
||
70 | |||
71 | /** |
||
72 | * Create a blank canvas of a given size, with a given background color. |
||
73 | * |
||
74 | * @param integer $width Image size, in pixels. |
||
75 | * @param integer $height Image height, in pixels. |
||
76 | * @param string $color Default to transparent. |
||
77 | * @throws InvalidArgumentException If the size arguments are not valid. |
||
78 | * @return Image Chainable |
||
79 | */ |
||
80 | public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)') |
||
98 | |||
99 | /** |
||
100 | * Open an image file |
||
101 | * |
||
102 | * @param string $source The source path / filename. |
||
103 | * @throws Exception If the source file does not exist. |
||
104 | * @throws InvalidArgumentException If the source argument is not a string. |
||
105 | * @return Image Chainable |
||
106 | */ |
||
107 | View Code Duplication | public function open($source = null) |
|
125 | |||
126 | /** |
||
127 | * Save an image to a target. |
||
128 | * If no target is set, the original source will be owerwritten |
||
129 | * |
||
130 | * @param string $target The target path / filename. |
||
131 | * @throws Exception If the target file does not exist or is not writeable. |
||
132 | * @throws InvalidArgumentException If the target argument is not a string. |
||
133 | * @return Image Chainable |
||
134 | */ |
||
135 | View Code Duplication | public function save($target = null) |
|
151 | |||
152 | /** |
||
153 | * Get the image's width, in pixels |
||
154 | * |
||
155 | * @return integer |
||
156 | */ |
||
157 | View Code Duplication | public function width() |
|
165 | |||
166 | /** |
||
167 | * Get the image's height, in pixels |
||
168 | * |
||
169 | * @return integer |
||
170 | */ |
||
171 | View Code Duplication | public function height() |
|
179 | |||
180 | /** |
||
181 | * @param string $channel The channel name to convert. |
||
182 | * @return string |
||
183 | */ |
||
184 | public function convertChannel($channel) |
||
188 | |||
189 | /** |
||
190 | * Find a command. |
||
191 | * |
||
192 | * Try (as best as possible) to find a command name: |
||
193 | * |
||
194 | * - With `type -p` |
||
195 | * - Or else, with `where` |
||
196 | * - Or else, with `which` |
||
197 | * |
||
198 | * @param string $cmdName The command name to find. |
||
199 | * @throws InvalidArgumentException If the given command name is not a string. |
||
200 | * @throws OutOfBoundsException If the command is unsupported or can not be found. |
||
201 | * @return string |
||
202 | */ |
||
203 | protected function findCmd($cmdName) |
||
242 | |||
243 | /** |
||
244 | * Retrieve the list of available commands. |
||
245 | * |
||
246 | * @return array |
||
247 | */ |
||
248 | public function availableCommands() |
||
252 | |||
253 | /** |
||
254 | * Retrieve the list of available commands. |
||
255 | * |
||
256 | * @param string $name The name of an available command. |
||
257 | * @throws InvalidArgumentException If the name is not a string. |
||
258 | * @throws OutOfBoundsException If the name is unsupported. |
||
259 | * @return array |
||
260 | */ |
||
261 | public function cmd($name) |
||
293 | |||
294 | /** |
||
295 | * @return string The full path of the mogrify command. |
||
296 | */ |
||
297 | public function mogrifyCmd() |
||
305 | |||
306 | /** |
||
307 | * @return string The full path of the convert command. |
||
308 | */ |
||
309 | public function convertCmd() |
||
317 | |||
318 | /** |
||
319 | * @return string The full path of the composite command. |
||
320 | */ |
||
321 | public function compositeCmd() |
||
329 | |||
330 | /** |
||
331 | * @return string The full path of the identify comand. |
||
332 | */ |
||
333 | public function identifyCmd() |
||
341 | |||
342 | /** |
||
343 | * Generate a temporary file, to apply effects on. |
||
344 | * |
||
345 | * @return string |
||
346 | */ |
||
347 | public function tmp() |
||
356 | |||
357 | /** |
||
358 | * @return ImagemagickImage Chainable |
||
359 | */ |
||
360 | public function resetTmp() |
||
368 | |||
369 | /** |
||
370 | * Exec a command, either with `proc_open()` or `shell_exec()` |
||
371 | * |
||
372 | * The `proc_open()` method is preferred, as it allows to catch errors in |
||
373 | * the STDERR buffer (and throw Exception) but it might be disabled in some |
||
374 | * systems for security reasons. |
||
375 | * |
||
376 | * @param string $cmd The command to execute. |
||
377 | * @throws Exception If the command fails. |
||
378 | * @return string |
||
379 | */ |
||
380 | public function exec($cmd) |
||
410 | |||
411 | /** |
||
412 | * @param string $params The $cmd's arguments and options. |
||
413 | * @param string|null $cmd The command to run. |
||
414 | * @throws Exception If the tmp file was not properly set. |
||
415 | * @return ImagemagickImage Chainable |
||
416 | */ |
||
417 | public function applyCmd($params, $cmd = null) |
||
435 | |||
436 | /** |
||
437 | * Convert a gravity name (string) to an `Imagick::GRAVITY_*` constant (integer) |
||
438 | * |
||
439 | * @param string $gravity The standard gravity name. |
||
440 | * @throws InvalidArgumentException If the gravity argument is not a valid gravity. |
||
441 | * @return integer |
||
442 | */ |
||
443 | public function imagemagickGravity($gravity) |
||
463 | } |
||
464 |
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.