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 ErrorObject 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 ErrorObject, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
14 | class ErrorObject implements ObjectInterface { |
||
|
|||
15 | use AtMemberManager, HttpStatusCodeManager, LinksManager; |
||
16 | |||
17 | /** @var string */ |
||
18 | protected $id; |
||
19 | /** @var string */ |
||
20 | protected $code; |
||
21 | /** @var string */ |
||
22 | protected $title; |
||
23 | /** @var string */ |
||
24 | protected $detail; |
||
25 | /** @var array */ |
||
26 | protected $source = []; |
||
27 | /** @var MetaObject */ |
||
28 | protected $meta; |
||
29 | /** @var array */ |
||
30 | protected static $defaults = [ |
||
31 | /** |
||
32 | * add the trace of exceptions when adding exceptions |
||
33 | * in some cases it might be handy to disable if traces are too big |
||
34 | */ |
||
35 | 'includeExceptionTrace' => true, |
||
36 | |||
37 | /** |
||
38 | * strip a base path from exception file and trace paths |
||
39 | * set this to the applications root to have more readable exception responses |
||
40 | */ |
||
41 | 'stripExceptionBasePath' => null, |
||
42 | ]; |
||
43 | |||
44 | /** |
||
45 | * @param string|int $genericCode developer-friendly code of the generic type of error |
||
46 | * @param string $genericTitle human-friendly title of the generic type of error |
||
47 | * @param string $specificDetails optional, human-friendly explanation of the specific error |
||
48 | * @param string $specificAboutLink optional, human-friendly explanation of the specific error |
||
49 | * @param string $genericTypeLink optional, human-friendly explanation of the generic type of error |
||
50 | */ |
||
51 | public function __construct($genericCode=null, $genericTitle=null, $specificDetails=null, $specificAboutLink=null, $genericTypeLink=null) { |
||
59 | |||
60 | /** |
||
61 | * human api |
||
62 | */ |
||
63 | |||
64 | /** |
||
65 | * @param \Exception|\Throwable $exception |
||
66 | * @param array $options optional {@see ErrorObject::$defaults} |
||
67 | * @return ErrorObject |
||
68 | * |
||
69 | * @throws InputException if $exception is not \Exception or \Throwable |
||
70 | */ |
||
71 | public static function fromException($exception, array $options=[]) { |
||
121 | |||
122 | /** |
||
123 | * explain this particular occurence of the error in a human-friendly way |
||
124 | * |
||
125 | * @param string $genericTitle title of the generic type of error |
||
126 | * @param string $specificDetails optional, explanation of the specific error |
||
127 | * @param string $specificAboutLink optional, explanation of the specific error |
||
128 | * @param string $genericTypeLink optional, explanation of the generic type of error |
||
129 | */ |
||
130 | public function setHumanExplanation($genericTitle, $specificDetails=null, $specificAboutLink=null, $genericTypeLink=null) { |
||
143 | |||
144 | /** |
||
145 | * set the link about this specific occurence of the error, explained in a human-friendly way |
||
146 | * |
||
147 | * @param string $href |
||
148 | * @param array $meta optional, if given a LinkObject is added, otherwise a link string is added |
||
149 | */ |
||
150 | public function setAboutLink($href, array $meta=[]) { |
||
153 | |||
154 | /** |
||
155 | * append a link of the generic type of this error, explained in a human-friendly way |
||
156 | * |
||
157 | * @param string $href |
||
158 | * @param array $meta optional, if given a LinkObject is added, otherwise a link string is added |
||
159 | */ |
||
160 | public function appendTypeLink($href, array $meta=[]) { |
||
163 | |||
164 | /** |
||
165 | * blame the json pointer from the request body causing this error |
||
166 | * |
||
167 | * @see https://tools.ietf.org/html/rfc6901 |
||
168 | * |
||
169 | * @param string $pointer e.g. "/data/attributes/title" or "/data" |
||
170 | */ |
||
171 | public function blameJsonPointer($pointer) { |
||
174 | |||
175 | /** |
||
176 | * blame the query parameter from the request causing this error |
||
177 | * |
||
178 | * @param string $parameter |
||
179 | */ |
||
180 | public function blameQueryParameter($parameter) { |
||
183 | |||
184 | /** |
||
185 | * @param string $key |
||
186 | * @param mixed $value |
||
187 | */ |
||
188 | public function addMeta($key, $value) { |
||
195 | |||
196 | /** |
||
197 | * spec api |
||
198 | */ |
||
199 | |||
200 | /** |
||
201 | * a unique identifier for this specific occurrence of the error |
||
202 | * |
||
203 | * @param string|int $id |
||
204 | */ |
||
205 | public function setUniqueIdentifier($id) { |
||
208 | |||
209 | /** |
||
210 | * a code expressing the generic type of this error |
||
211 | * it should be application-specific and aimed at developers |
||
212 | * |
||
213 | * @param string|int $genericCode will be casted to a string |
||
214 | */ |
||
215 | public function setApplicationCode($genericCode) { |
||
218 | |||
219 | /** |
||
220 | * add the source of the error |
||
221 | * |
||
222 | * @param string $key {@see ->blameJsonPointer(), ->blameQueryParameter()} |
||
223 | * @param string $value |
||
224 | */ |
||
225 | public function addSource($key, $value) { |
||
230 | |||
231 | /** |
||
232 | * a short human-friendly explanation of the generic type of this error |
||
233 | * |
||
234 | * @param string $genericTitle |
||
235 | */ |
||
236 | public function setHumanTitle($genericTitle) { |
||
239 | |||
240 | /** |
||
241 | * a human-friendly explanation of this specific occurrence of the error |
||
242 | * |
||
243 | * @param string $specificDetails |
||
244 | */ |
||
245 | public function setHumanDetails($specificDetails) { |
||
248 | |||
249 | /** |
||
250 | * @param MetaObject $metaObject |
||
251 | */ |
||
252 | public function setMetaObject(MetaObject $metaObject) { |
||
255 | |||
256 | /** |
||
257 | * ObjectInterface |
||
258 | */ |
||
259 | |||
260 | /** |
||
261 | * @inheritDoc |
||
262 | */ |
||
263 | public function isEmpty() { |
||
294 | |||
295 | /** |
||
296 | * @inheritDoc |
||
297 | */ |
||
298 | public function toArray() { |
||
328 | } |
||
329 |