Complex classes like JSend 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 JSend, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | class JSend implements JsonSerializable |
||
13 | { |
||
14 | const STATUS_SUCCESS = 'success'; |
||
15 | |||
16 | const STATUS_ERROR = 'error'; |
||
17 | |||
18 | const STATUS_FAIL = 'fail'; |
||
19 | |||
20 | /** |
||
21 | * JSend status |
||
22 | * |
||
23 | * @var string |
||
24 | */ |
||
25 | protected $status; |
||
26 | |||
27 | /** |
||
28 | * JSend Data |
||
29 | * |
||
30 | * @var array |
||
31 | */ |
||
32 | protected $data; |
||
33 | |||
34 | /** |
||
35 | * JSend Error Message |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | protected $errorMessage; |
||
40 | |||
41 | /** |
||
42 | * JSend Error Code |
||
43 | * @var int|null |
||
44 | */ |
||
45 | protected $errorCode; |
||
46 | |||
47 | /** |
||
48 | * New Instance |
||
49 | * |
||
50 | * @param string $status |
||
51 | * @param mixed $data |
||
52 | * @param string $errorMessage |
||
53 | * @param int $errorCode |
||
54 | */ |
||
55 | 96 | public function __construct($status, $data = null, $errorMessage = null, $errorCode = null) |
|
56 | { |
||
57 | 96 | $this->status = $this->filterStatus($status); |
|
58 | 96 | $this->data = $this->filterData($data); |
|
59 | 96 | list($this->errorMessage, $this->errorCode) = $this->filterError($errorMessage, $errorCode); |
|
60 | 96 | } |
|
61 | |||
62 | /** |
||
63 | * Filter and Validate the JSend Status |
||
64 | * |
||
65 | * @param string $status |
||
66 | * |
||
67 | * @throws UnexpectedValueException If the status value does not conform to JSend Spec. |
||
68 | * |
||
69 | * @return string |
||
70 | */ |
||
71 | 96 | protected function filterStatus($status) |
|
80 | |||
81 | /** |
||
82 | * Filter and Validate the JSend Data |
||
83 | * |
||
84 | * @param mixed $data The data can be |
||
85 | * <ul> |
||
86 | * <li>An Array |
||
87 | * <li>A JsonSerializable object |
||
88 | * <li>null |
||
89 | * </ul> |
||
90 | * |
||
91 | * @throws UnexpectedValueException If the input does not conform to one of the valid type |
||
92 | * |
||
93 | * @return array |
||
94 | */ |
||
95 | 96 | protected function filterData($data) |
|
111 | |||
112 | /** |
||
113 | * Filter and Validate the JSend Error properties |
||
114 | * |
||
115 | * @param string $errorMessage |
||
116 | * @param int $errorCode |
||
117 | */ |
||
118 | 96 | protected function filterError($errorMessage, $errorCode) |
|
126 | |||
127 | /** |
||
128 | * Validate a string |
||
129 | * |
||
130 | * @param mixed $str |
||
131 | * |
||
132 | * @throws UnexpectedValueException If the data value is not a empty string |
||
133 | * |
||
134 | * @return string |
||
135 | */ |
||
136 | 30 | protected function validateErrorMessage($str) |
|
147 | |||
148 | /** |
||
149 | * Validate a integer |
||
150 | * |
||
151 | * @param mixed $int |
||
152 | * |
||
153 | * @throws UnexpectedValueException If the data value is not an integer |
||
154 | * |
||
155 | * @return int |
||
156 | */ |
||
157 | 24 | protected function validateErrorCode($int) |
|
169 | |||
170 | /** |
||
171 | * Returns the status |
||
172 | * |
||
173 | * @return string |
||
174 | */ |
||
175 | 39 | public function getStatus() |
|
179 | |||
180 | /** |
||
181 | * Returns the data |
||
182 | * |
||
183 | * @return array |
||
184 | */ |
||
185 | 33 | public function getData() |
|
189 | |||
190 | /** |
||
191 | * Returns the error message |
||
192 | * |
||
193 | * @return string |
||
194 | */ |
||
195 | 12 | public function getErrorMessage() |
|
199 | |||
200 | /** |
||
201 | * Returns the error code |
||
202 | * |
||
203 | * @return int|null |
||
204 | */ |
||
205 | 15 | public function getErrorCode() |
|
209 | |||
210 | /** |
||
211 | * Returns whether the status is success |
||
212 | * |
||
213 | * @return bool |
||
214 | */ |
||
215 | 9 | public function isSuccess() |
|
219 | |||
220 | /** |
||
221 | * Returns whether the status is fail |
||
222 | * |
||
223 | * @return bool |
||
224 | */ |
||
225 | 9 | public function isFail() |
|
229 | |||
230 | /** |
||
231 | * Returns whether the status is error |
||
232 | * |
||
233 | * @return bool |
||
234 | */ |
||
235 | 15 | public function isError() |
|
239 | |||
240 | /** |
||
241 | * @inheritdoc |
||
242 | */ |
||
243 | 45 | public function __toString() |
|
247 | |||
248 | /** |
||
249 | * @inheritdoc |
||
250 | */ |
||
251 | 45 | public function jsonSerialize() |
|
255 | |||
256 | /** |
||
257 | * Retuns the array representation |
||
258 | * |
||
259 | * @return array |
||
260 | */ |
||
261 | 48 | public function toArray() |
|
279 | |||
280 | /** |
||
281 | * @inheritdoc |
||
282 | */ |
||
283 | 3 | public function __debugInfo() |
|
287 | |||
288 | /** |
||
289 | * Returns the generated HTTP Response |
||
290 | * |
||
291 | * @param array $headers Optional headers to add to the response |
||
292 | * |
||
293 | * @return string |
||
294 | */ |
||
295 | 12 | public function send(array $headers = []) |
|
307 | |||
308 | /** |
||
309 | * Filter Submitted Headers |
||
310 | * |
||
311 | * @param array $headers a Collection of key/value headers |
||
312 | * |
||
313 | * @return array |
||
314 | */ |
||
315 | 12 | protected function filterHeaders(array $headers) |
|
324 | |||
325 | /** |
||
326 | * Validate Header name |
||
327 | * |
||
328 | * @param string $name |
||
329 | * |
||
330 | * @throws InvalidArgumentException if the header name is invalid |
||
331 | * |
||
332 | * @return string |
||
333 | */ |
||
334 | 12 | protected function validateHeaderName($name) |
|
342 | |||
343 | /** |
||
344 | * Validate Header value |
||
345 | * |
||
346 | * @param string $value |
||
347 | * |
||
348 | * @throws InvalidArgumentException if the header value is invalid |
||
349 | * |
||
350 | * @return string |
||
351 | */ |
||
352 | 12 | protected function validateHeaderValue($value) |
|
362 | |||
363 | /** |
||
364 | * Returns an instance with the specified status. |
||
365 | * |
||
366 | * This method MUST retain the state of the current instance, and return |
||
367 | * an instance that contains the specified status. |
||
368 | * |
||
369 | * @param string $status The status to use with the new instance. |
||
370 | * |
||
371 | * @return static A new instance with the specified status. |
||
372 | */ |
||
373 | 6 | public function withStatus($status) |
|
381 | |||
382 | /** |
||
383 | * Returns an instance with the specified data. |
||
384 | * |
||
385 | * This method MUST retain the state of the current instance, and return |
||
386 | * an instance that contains the specified data. |
||
387 | * |
||
388 | * @param mixed $data The data to use with the new instance. |
||
389 | * |
||
390 | * @return static A new instance with the specified data. |
||
391 | */ |
||
392 | 6 | public function withData($data) |
|
401 | |||
402 | /** |
||
403 | * Returns an instance with the specified error message and error code. |
||
404 | * |
||
405 | * This method MUST retain the state of the current instance, and return |
||
406 | * an instance that contains the specified error message and error code. |
||
407 | * |
||
408 | * @param string $errorMessage The error message to use with the new instance. |
||
409 | * @param int|null $errorCode The error code to use with the new instance. |
||
410 | * |
||
411 | * @return static A new instance with the specified status. |
||
412 | */ |
||
413 | 6 | public function withError($errorMessage, $errorCode = null) |
|
421 | |||
422 | /** |
||
423 | * Returns a successful JSend object with the specified data |
||
424 | * |
||
425 | * @param mixed $data The data to use with the new instance. |
||
426 | * |
||
427 | * @return static A new succesful instance with the specified data. |
||
428 | */ |
||
429 | 6 | public static function success($data = null) |
|
433 | |||
434 | /** |
||
435 | * Returns a failed JSend object with the specified data |
||
436 | * |
||
437 | * @param mixed $data The data to use with the new instance. |
||
438 | * |
||
439 | * @return static A new failed instance with the specified data. |
||
440 | */ |
||
441 | 3 | public static function fail($data = null) |
|
445 | |||
446 | /** |
||
447 | * Returns a error JSend object with the specified error message and error code. |
||
448 | * |
||
449 | * @param string $errorMessage The error message to use with the new instance. |
||
450 | * @param int|null $errorCode The error code to use with the new instance. |
||
451 | * @param array $data The optional data to use with the new instance. |
||
452 | * |
||
453 | * @return static A new failed instance with the specified data. |
||
454 | */ |
||
455 | 9 | public static function error($errorMessage, $errorCode = null, $data = null) |
|
459 | |||
460 | /** |
||
461 | * Returns a new instance from a JSON string |
||
462 | * |
||
463 | * @param string $json The string being decoded |
||
464 | * @param int $depth User specified recursion depth. |
||
465 | * @param int $options Bitmask of JSON decode options |
||
466 | * |
||
467 | * @throws InvalidArgumentException If the string can not be decode |
||
468 | * |
||
469 | * @return static |
||
470 | */ |
||
471 | 6 | public static function createFromString($json, $depth = 512, $options = 0) |
|
483 | |||
484 | /** |
||
485 | * @inheritdoc |
||
486 | */ |
||
487 | 3 | public static function __set_state(array $properties) |
|
491 | |||
492 | /** |
||
493 | * Returns a new instance from an array |
||
494 | * |
||
495 | * @param array $arr The array to build a new JSend object with |
||
496 | * |
||
497 | * @return static |
||
498 | */ |
||
499 | 9 | public static function createFromArray(array $arr) |
|
506 | } |
||
507 |
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.