Complex classes like Image 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 Image, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class Image implements \ArrayAccess |
||
18 | { |
||
19 | /** |
||
20 | * @var string The new image name, to be provided or will be generated. |
||
21 | */ |
||
22 | protected $name; |
||
23 | |||
24 | /** |
||
25 | * @var int The image width in pixels |
||
26 | */ |
||
27 | protected $width; |
||
28 | |||
29 | /** |
||
30 | * @var int The image height in pixels |
||
31 | */ |
||
32 | protected $height; |
||
33 | |||
34 | /** |
||
35 | * @var string The image mime type (extension) |
||
36 | */ |
||
37 | protected $mime; |
||
38 | |||
39 | /** |
||
40 | * @var string The full image path (dir + image + mime) |
||
41 | */ |
||
42 | protected $fullPath; |
||
43 | |||
44 | /** |
||
45 | * @var string The folder or image storage location |
||
46 | */ |
||
47 | protected $location; |
||
48 | |||
49 | /** |
||
50 | * @var array A json format of all information about an image |
||
51 | */ |
||
52 | protected $serialize = array(); |
||
53 | |||
54 | /** |
||
55 | * @var array The min and max image size allowed for upload (in bytes) |
||
56 | */ |
||
57 | protected $size = array(100, 500000); |
||
58 | |||
59 | /** |
||
60 | * @var array The max height and width image allowed |
||
61 | */ |
||
62 | protected $dimensions = array(5000, 5000); |
||
63 | |||
64 | /** |
||
65 | * @var array The mime types allowed for upload |
||
66 | */ |
||
67 | protected $mimeTypes = array("jpeg", "png", "gif"); |
||
68 | |||
69 | /** |
||
70 | * @var array list of known image types |
||
71 | */ |
||
72 | protected $imageMimes = array( |
||
73 | 1 => "gif", "jpeg", "png", "swf", "psd", |
||
74 | "bmp", "tiff", "tiff", "jpc", "jp2", "jpx", |
||
75 | "jb2", "swc", "iff", "wbmp", "xbm", "ico" |
||
76 | ); |
||
77 | |||
78 | /** |
||
79 | * @var array storage for the $_FILES global array |
||
80 | */ |
||
81 | private $_files = array(); |
||
82 | |||
83 | /** |
||
84 | * @var string storage for any errors |
||
85 | */ |
||
86 | private $error = ""; |
||
87 | |||
88 | /** |
||
89 | * @var array error messages strings |
||
90 | */ |
||
91 | protected $common_upload_errors = array( |
||
92 | UPLOAD_ERR_OK => "", |
||
93 | UPLOAD_ERR_INI_SIZE => "Image is larger than the specified amount set by the server", |
||
94 | UPLOAD_ERR_FORM_SIZE => "Image is larger than the specified amount specified by browser", |
||
95 | UPLOAD_ERR_PARTIAL => "Image could not be fully uploaded. Please try again later", |
||
96 | UPLOAD_ERR_NO_FILE => "Image is not found", |
||
97 | UPLOAD_ERR_NO_TMP_DIR => "Can't write to disk, due to server configuration ( No tmp dir found )", |
||
98 | UPLOAD_ERR_CANT_WRITE => "Failed to write file to disk. Please check you file permissions", |
||
99 | UPLOAD_ERR_EXTENSION => "A PHP extension has halted this file upload process" |
||
100 | ); |
||
101 | |||
102 | /** |
||
103 | * @param array $_files represents the $_FILES array passed as dependency |
||
104 | */ |
||
105 | public function __construct(array $_files = array()) |
||
115 | |||
116 | /** |
||
117 | * Gets the real image mime type |
||
118 | * |
||
119 | * @param $tmp_name string The upload tmp directory |
||
120 | * |
||
121 | * @return bool|string |
||
122 | */ |
||
123 | protected function getImageMime($tmp_name) |
||
133 | |||
134 | /** |
||
135 | * @param mixed $offset |
||
136 | * @param mixed $value |
||
137 | */ |
||
138 | public function offsetSet($offset, $value) |
||
141 | |||
142 | /** |
||
143 | * @param mixed $offset |
||
144 | * @return null |
||
145 | */ |
||
146 | public function offsetExists($offset) |
||
149 | |||
150 | /** |
||
151 | * @param mixed $offset |
||
152 | */ |
||
153 | public function offsetUnset($offset) |
||
156 | |||
157 | /** |
||
158 | * Gets array value \ArrayAccess |
||
159 | * |
||
160 | * @param mixed $offset |
||
161 | * |
||
162 | * @return bool|mixed |
||
163 | */ |
||
164 | public function offsetGet($offset) |
||
177 | |||
178 | |||
179 | /** |
||
180 | * Provide image name if not provided |
||
181 | * |
||
182 | * @param null $isNameProvided |
||
183 | * @return $this |
||
184 | */ |
||
185 | public function setName($isNameProvided = null) |
||
193 | |||
194 | /** |
||
195 | * Define a mime type for uploading |
||
196 | * |
||
197 | * @param array $fileTypes |
||
198 | * |
||
199 | * @return $this |
||
200 | */ |
||
201 | public function setMime(array $fileTypes) |
||
206 | |||
207 | /** |
||
208 | * Define a min and max image size for uploading |
||
209 | * |
||
210 | * @param $min int minimum value in bytes |
||
211 | * @param $max int maximum value in bytes |
||
212 | * |
||
213 | * @return $this |
||
214 | */ |
||
215 | public function setSize($min, $max) |
||
220 | |||
221 | /** |
||
222 | * Creates a location for upload storage |
||
223 | * |
||
224 | * @param $dir string the folder name to create |
||
225 | * @param int $permission chmod permission |
||
226 | * |
||
227 | * @return $this |
||
228 | */ |
||
229 | public function setLocation($dir = "bulletproof", $permission = 0666) |
||
242 | |||
243 | /** |
||
244 | * Sets acceptable max image height and width |
||
245 | * |
||
246 | * @param $maxWidth int max width value |
||
247 | * @param $maxHeight int max height value |
||
248 | * |
||
249 | * @return $this |
||
250 | */ |
||
251 | public function setDimension($maxWidth, $maxHeight) |
||
256 | |||
257 | /** |
||
258 | * Returns the image name |
||
259 | * |
||
260 | * @return string |
||
261 | */ |
||
262 | public function getName() |
||
270 | |||
271 | /** |
||
272 | * Returns the full path of the image ex "location/image.mime" |
||
273 | * |
||
274 | * @return string |
||
275 | */ |
||
276 | public function getFullPath() |
||
281 | |||
282 | /** |
||
283 | * Returns the image size in bytes |
||
284 | * |
||
285 | * @return int |
||
286 | */ |
||
287 | public function getSize() |
||
291 | |||
292 | /** |
||
293 | * Returns the image height in pixels |
||
294 | * |
||
295 | * @return int |
||
296 | */ |
||
297 | public function getHeight() |
||
306 | |||
307 | /** |
||
308 | * Returns the image width |
||
309 | * |
||
310 | * @return int |
||
311 | */ |
||
312 | public function getWidth() |
||
321 | |||
322 | /** |
||
323 | * Returns the storage / folder name |
||
324 | * |
||
325 | * @return string |
||
326 | */ |
||
327 | public function getLocation() |
||
335 | |||
336 | /** |
||
337 | * Returns a JSON format of the image width, height, name, mime ... |
||
338 | * |
||
339 | * @return string |
||
340 | */ |
||
341 | public function getJson() |
||
345 | |||
346 | /** |
||
347 | * Returns the image mime type |
||
348 | * |
||
349 | * @return string |
||
350 | */ |
||
351 | public function getMime() |
||
358 | |||
359 | /** |
||
360 | * Returns error string or false if no errors occurred |
||
361 | * |
||
362 | * @return string|bool |
||
363 | */ |
||
364 | public function getError() |
||
368 | |||
369 | /** |
||
370 | * Checks for the common upload errors |
||
371 | * |
||
372 | * @param $e int error constant |
||
373 | */ |
||
374 | protected function commonUploadErrors($e) |
||
378 | |||
379 | /** |
||
380 | * This methods validates and uploads the image |
||
381 | * @return bool|Image|null |
||
382 | */ |
||
383 | public function upload() |
||
458 | |||
459 | /** |
||
460 | * Final upload method to be called, isolated for testing purposes |
||
461 | * |
||
462 | * @param $tmp_name int the temporary location of the image file |
||
463 | * @param $destination int upload destination |
||
464 | * |
||
465 | * @return bool |
||
466 | */ |
||
467 | public function moveUploadedFile($tmp_name, $destination) |
||
471 | } |
||
472 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.