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 Comment 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 Comment, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 30 | class Comment implements IComment { |
||
| 31 | |||
| 32 | protected $data = [ |
||
| 33 | 'id' => '', |
||
| 34 | 'parentId' => '0', |
||
| 35 | 'topmostParentId' => '0', |
||
| 36 | 'childrenCount' => '0', |
||
| 37 | 'message' => '', |
||
| 38 | 'verb' => '', |
||
| 39 | 'actorType' => '', |
||
| 40 | 'actorId' => '', |
||
| 41 | 'objectType' => '', |
||
| 42 | 'objectId' => '', |
||
| 43 | 'creationDT' => null, |
||
| 44 | 'latestChildDT' => null, |
||
| 45 | ]; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Comment constructor. |
||
| 49 | * |
||
| 50 | * @param array $data optional, array with keys according to column names from |
||
| 51 | * the comments database scheme |
||
| 52 | */ |
||
| 53 | public function __construct(array $data = null) { |
||
| 58 | |||
| 59 | /** |
||
| 60 | * returns the ID of the comment |
||
| 61 | * |
||
| 62 | * It may return an empty string, if the comment was not stored. |
||
| 63 | * It is expected that the concrete Comment implementation gives an ID |
||
| 64 | * by itself (e.g. after saving). |
||
| 65 | * |
||
| 66 | * @return string |
||
| 67 | * @since 9.0.0 |
||
| 68 | */ |
||
| 69 | public function getId() { |
||
| 72 | |||
| 73 | /** |
||
| 74 | * sets the ID of the comment and returns itself |
||
| 75 | * |
||
| 76 | * It is only allowed to set the ID only, if the current id is an empty |
||
| 77 | * string (which means it is not stored in a database, storage or whatever |
||
| 78 | * the concrete implementation does), or vice versa. Changing a given ID is |
||
| 79 | * not permitted and must result in an IllegalIDChangeException. |
||
| 80 | * |
||
| 81 | * @param string $id |
||
| 82 | * @return IComment |
||
| 83 | * @throws IllegalIDChangeException |
||
| 84 | * @since 9.0.0 |
||
| 85 | */ |
||
| 86 | public function setId($id) { |
||
| 99 | |||
| 100 | /** |
||
| 101 | * returns the parent ID of the comment |
||
| 102 | * |
||
| 103 | * @return string |
||
| 104 | * @since 9.0.0 |
||
| 105 | */ |
||
| 106 | public function getParentId() { |
||
| 109 | |||
| 110 | /** |
||
| 111 | * sets the parent ID and returns itself |
||
| 112 | * |
||
| 113 | * @param string $parentId |
||
| 114 | * @return IComment |
||
| 115 | * @since 9.0.0 |
||
| 116 | */ |
||
| 117 | public function setParentId($parentId) { |
||
| 124 | |||
| 125 | /** |
||
| 126 | * returns the topmost parent ID of the comment |
||
| 127 | * |
||
| 128 | * @return string |
||
| 129 | * @since 9.0.0 |
||
| 130 | */ |
||
| 131 | public function getTopmostParentId() { |
||
| 134 | |||
| 135 | |||
| 136 | /** |
||
| 137 | * sets the topmost parent ID and returns itself |
||
| 138 | * |
||
| 139 | * @param string $id |
||
| 140 | * @return IComment |
||
| 141 | * @since 9.0.0 |
||
| 142 | */ |
||
| 143 | View Code Duplication | public function setTopmostParentId($id) { |
|
| 150 | |||
| 151 | /** |
||
| 152 | * returns the number of children |
||
| 153 | * |
||
| 154 | * @return int |
||
| 155 | * @since 9.0.0 |
||
| 156 | */ |
||
| 157 | public function getChildrenCount() { |
||
| 160 | |||
| 161 | /** |
||
| 162 | * sets the number of children |
||
| 163 | * |
||
| 164 | * @param int $count |
||
| 165 | * @return IComment |
||
| 166 | * @since 9.0.0 |
||
| 167 | */ |
||
| 168 | public function setChildrenCount($count) { |
||
| 175 | |||
| 176 | /** |
||
| 177 | * returns the message of the comment |
||
| 178 | * |
||
| 179 | * @return string |
||
| 180 | * @since 9.0.0 |
||
| 181 | */ |
||
| 182 | public function getMessage() { |
||
| 185 | |||
| 186 | /** |
||
| 187 | * sets the message of the comment and returns itself |
||
| 188 | * |
||
| 189 | * @param string $message |
||
| 190 | * @return IComment |
||
| 191 | * @throws MessageTooLongException |
||
| 192 | * @since 9.0.0 |
||
| 193 | */ |
||
| 194 | public function setMessage($message) { |
||
| 205 | |||
| 206 | /** |
||
| 207 | * returns an array containing mentions that are included in the comment |
||
| 208 | * |
||
| 209 | * @return array each mention provides a 'type' and an 'id', see example below |
||
| 210 | * @since 9.2.0 |
||
| 211 | * |
||
| 212 | * The return array looks like: |
||
| 213 | * [ |
||
| 214 | * [ |
||
| 215 | * 'type' => 'user', |
||
| 216 | * 'id' => 'citizen4' |
||
| 217 | * ], |
||
| 218 | * [ |
||
| 219 | * 'type' => 'group', |
||
| 220 | * 'id' => 'media' |
||
| 221 | * ], |
||
| 222 | * … |
||
| 223 | * ] |
||
| 224 | * |
||
| 225 | */ |
||
| 226 | public function getMentions() { |
||
| 242 | |||
| 243 | /** |
||
| 244 | * returns the verb of the comment |
||
| 245 | * |
||
| 246 | * @return string |
||
| 247 | * @since 9.0.0 |
||
| 248 | */ |
||
| 249 | public function getVerb() { |
||
| 252 | |||
| 253 | /** |
||
| 254 | * sets the verb of the comment, e.g. 'comment' or 'like' |
||
| 255 | * |
||
| 256 | * @param string $verb |
||
| 257 | * @return IComment |
||
| 258 | * @since 9.0.0 |
||
| 259 | */ |
||
| 260 | View Code Duplication | public function setVerb($verb) { |
|
| 267 | |||
| 268 | /** |
||
| 269 | * returns the actor type |
||
| 270 | * |
||
| 271 | * @return string |
||
| 272 | * @since 9.0.0 |
||
| 273 | */ |
||
| 274 | public function getActorType() { |
||
| 277 | |||
| 278 | /** |
||
| 279 | * returns the actor ID |
||
| 280 | * |
||
| 281 | * @return string |
||
| 282 | * @since 9.0.0 |
||
| 283 | */ |
||
| 284 | public function getActorId() { |
||
| 287 | |||
| 288 | /** |
||
| 289 | * sets (overwrites) the actor type and id |
||
| 290 | * |
||
| 291 | * @param string $actorType e.g. 'users' |
||
| 292 | * @param string $actorId e.g. 'zombie234' |
||
| 293 | * @return IComment |
||
| 294 | * @since 9.0.0 |
||
| 295 | */ |
||
| 296 | public function setActor($actorType, $actorId) { |
||
| 307 | |||
| 308 | /** |
||
| 309 | * returns the creation date of the comment. |
||
| 310 | * |
||
| 311 | * If not explicitly set, it shall default to the time of initialization. |
||
| 312 | * |
||
| 313 | * @return \DateTime |
||
| 314 | * @since 9.0.0 |
||
| 315 | */ |
||
| 316 | public function getCreationDateTime() { |
||
| 319 | |||
| 320 | /** |
||
| 321 | * sets the creation date of the comment and returns itself |
||
| 322 | * |
||
| 323 | * @param \DateTime $timestamp |
||
| 324 | * @return IComment |
||
| 325 | * @since 9.0.0 |
||
| 326 | */ |
||
| 327 | public function setCreationDateTime(\DateTime $timestamp) { |
||
| 331 | |||
| 332 | /** |
||
| 333 | * returns the DateTime of the most recent child, if set, otherwise null |
||
| 334 | * |
||
| 335 | * @return \DateTime|null |
||
| 336 | * @since 9.0.0 |
||
| 337 | */ |
||
| 338 | public function getLatestChildDateTime() { |
||
| 341 | |||
| 342 | /** |
||
| 343 | * sets the date of the most recent child |
||
| 344 | * |
||
| 345 | * @param \DateTime $dateTime |
||
| 346 | * @return IComment |
||
| 347 | * @since 9.0.0 |
||
| 348 | */ |
||
| 349 | public function setLatestChildDateTime(\DateTime $dateTime = null) { |
||
| 353 | |||
| 354 | /** |
||
| 355 | * returns the object type the comment is attached to |
||
| 356 | * |
||
| 357 | * @return string |
||
| 358 | * @since 9.0.0 |
||
| 359 | */ |
||
| 360 | public function getObjectType() { |
||
| 363 | |||
| 364 | /** |
||
| 365 | * returns the object id the comment is attached to |
||
| 366 | * |
||
| 367 | * @return string |
||
| 368 | * @since 9.0.0 |
||
| 369 | */ |
||
| 370 | public function getObjectId() { |
||
| 373 | |||
| 374 | /** |
||
| 375 | * sets (overwrites) the object of the comment |
||
| 376 | * |
||
| 377 | * @param string $objectType e.g. 'files' |
||
| 378 | * @param string $objectId e.g. '16435' |
||
| 379 | * @return IComment |
||
| 380 | * @since 9.0.0 |
||
| 381 | */ |
||
| 382 | public function setObject($objectType, $objectId) { |
||
| 393 | |||
| 394 | /** |
||
| 395 | * sets the comment data based on an array with keys as taken from the |
||
| 396 | * database. |
||
| 397 | * |
||
| 398 | * @param array $data |
||
| 399 | * @return IComment |
||
| 400 | */ |
||
| 401 | protected function fromArray($data) { |
||
| 421 | } |
||
| 422 |
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.