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 MimePart 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 MimePart, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 24 | class MimePart |
||
| 25 | { |
||
| 26 | /** |
||
| 27 | * @var \ZBateson\MailMimeParser\Header\HeaderFactory the HeaderFactory |
||
| 28 | * object used for created headers |
||
| 29 | */ |
||
| 30 | protected $headerFactory; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @var \ZBateson\MailMimeParser\Header\AbstractHeader[] array of header |
||
| 34 | * objects |
||
| 35 | */ |
||
| 36 | protected $headers; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @var \ZBateson\MailMimeParser\Message\MimePart parent part |
||
| 40 | */ |
||
| 41 | protected $parent; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @var resource the content's resource handle |
||
| 45 | */ |
||
| 46 | protected $handle; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var \ZBateson\MailMimeParser\Message\MimePart[] array of parts in this |
||
| 50 | * message |
||
| 51 | */ |
||
| 52 | protected $parts = []; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @var \ZBateson\MailMimeParser\Message\MimePart[][] Maps mime types to |
||
| 56 | * parts for looking up in getPartByMimeType |
||
| 57 | */ |
||
| 58 | protected $mimeToPart = []; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * @var \ZBateson\MailMimeParser\Message\Writer\MimePartWriter the part |
||
| 62 | * writer for this MimePart |
||
| 63 | */ |
||
| 64 | protected $partWriter = null; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Sets up class dependencies. |
||
| 68 | * |
||
| 69 | * @param HeaderFactory $headerFactory |
||
| 70 | * @param MimePartWriter $partWriter |
||
| 71 | */ |
||
| 72 | 91 | public function __construct(HeaderFactory $headerFactory, MimePartWriter $partWriter) |
|
| 77 | |||
| 78 | /** |
||
| 79 | * Closes the attached resource handle. |
||
| 80 | */ |
||
| 81 | 91 | public function __destruct() |
|
| 87 | |||
| 88 | /** |
||
| 89 | * Adds the passed part to the parts array, and registers non-attachment/ |
||
| 90 | * non-multipart parts by their content type. |
||
| 91 | * |
||
| 92 | * If the $position parameter is non-null, adds the part at the passed |
||
| 93 | * position index. |
||
| 94 | * |
||
| 95 | * @param \ZBateson\MailMimeParser\Message\MimePart $part |
||
| 96 | * @param int $position |
||
| 97 | */ |
||
| 98 | 83 | public function addPart(MimePart $part, $position = null) |
|
| 107 | |||
| 108 | /** |
||
| 109 | * Registers non-attachment parts in the mime type registry |
||
| 110 | * |
||
| 111 | * @param \ZBateson\MailMimeParser\Message\MimePart $part |
||
| 112 | */ |
||
| 113 | 83 | protected function registerPart(MimePart $part) |
|
| 123 | |||
| 124 | /** |
||
| 125 | * Removes the part from the mime-type registry. |
||
| 126 | * |
||
| 127 | * @param \ZBateson\MailMimeParser\Message\MimePart $part |
||
| 128 | */ |
||
| 129 | 14 | protected function unregisterPart(MimePart $part) |
|
| 141 | |||
| 142 | /** |
||
| 143 | * Unregisters the child part from this part and returns its position or |
||
| 144 | * null if it wasn't found. |
||
| 145 | * |
||
| 146 | * @param \ZBateson\MailMimeParser\Message\MimePart $part |
||
| 147 | * @return int or null if not found |
||
| 148 | */ |
||
| 149 | 14 | public function removePart(MimePart $part) |
|
| 164 | |||
| 165 | /** |
||
| 166 | * Returns the part at the given 0-based index, or null if none is set. |
||
| 167 | * |
||
| 168 | * @param int $index |
||
| 169 | * @return \ZBateson\MailMimeParser\Message\MimePart |
||
| 170 | */ |
||
| 171 | 2 | public function getPart($index) |
|
| 179 | |||
| 180 | /** |
||
| 181 | * Returns all child parts, and child parts of all children. |
||
| 182 | * |
||
| 183 | * @return \ZBateson\MailMimeParser\Message\MimePart[] |
||
| 184 | */ |
||
| 185 | 11 | public function getAllParts() |
|
| 193 | |||
| 194 | /** |
||
| 195 | * Returns the total number of parts in this and all children. |
||
| 196 | * |
||
| 197 | * @return int |
||
| 198 | */ |
||
| 199 | 1 | public function getPartCount() |
|
| 208 | |||
| 209 | /** |
||
| 210 | * Returns the direct child at the given 0-based index, or null if none is |
||
| 211 | * set. |
||
| 212 | * |
||
| 213 | * @param int $index |
||
| 214 | * @return \ZBateson\MailMimeParser\Message\MimePart |
||
| 215 | */ |
||
| 216 | 9 | public function getChild($index) |
|
| 223 | |||
| 224 | /** |
||
| 225 | * Returns all direct child parts. |
||
| 226 | * |
||
| 227 | * @return \ZBateson\MailMimeParser\Message\MimePart[] |
||
| 228 | */ |
||
| 229 | 80 | public function getChildParts() |
|
| 233 | |||
| 234 | /** |
||
| 235 | * Returns the number of direct children under this part. |
||
| 236 | * |
||
| 237 | * @return \ZBateson\MailMimeParser\Message\MimePart[] |
||
| 238 | */ |
||
| 239 | 1 | public function getChildCount() |
|
| 243 | |||
| 244 | /** |
||
| 245 | * Returns the part associated with the passed mime type if it exists. |
||
| 246 | * |
||
| 247 | * @param string $mimeType |
||
| 248 | * @return \ZBateson\MailMimeParser\Message\MimePart or null |
||
| 249 | */ |
||
| 250 | 22 | View Code Duplication | public function getPartByMimeType($mimeType) |
| 258 | |||
| 259 | /** |
||
| 260 | * Returns an array of all parts associated with the passed mime type if any |
||
| 261 | * exist or null otherwise. |
||
| 262 | * |
||
| 263 | * @param string $mimeType |
||
| 264 | * @return \ZBateson\MailMimeParser\Message\MimePart[] or null |
||
| 265 | */ |
||
| 266 | View Code Duplication | public function getAllPartsByMimeType($mimeType) |
|
| 274 | |||
| 275 | /** |
||
| 276 | * Returns true if there's a content stream associated with the part. |
||
| 277 | * |
||
| 278 | * @return boolean |
||
| 279 | */ |
||
| 280 | 16 | public function hasContent() |
|
| 287 | |||
| 288 | /** |
||
| 289 | * Returns true if this part's mime type is multipart/* |
||
| 290 | * |
||
| 291 | * @return bool |
||
| 292 | */ |
||
| 293 | 83 | public function isMultiPart() |
|
| 300 | |||
| 301 | /** |
||
| 302 | * Returns true if this part's mime type is text/plain, text/html or has a |
||
| 303 | * text/* and has a defined 'charset' attribute. |
||
| 304 | * |
||
| 305 | * @return bool |
||
| 306 | */ |
||
| 307 | 83 | public function isTextPart() |
|
| 319 | |||
| 320 | /** |
||
| 321 | * Attaches the resource handle for the part's content. The attached handle |
||
| 322 | * is closed when the MimePart object is destroyed. |
||
| 323 | * |
||
| 324 | * @param resource $contentHandle |
||
| 325 | */ |
||
| 326 | 85 | public function attachContentResourceHandle($contentHandle) |
|
| 333 | |||
| 334 | /** |
||
| 335 | * Detaches the content resource handle from this part but does not close |
||
| 336 | * it. |
||
| 337 | */ |
||
| 338 | 14 | protected function detachContentResourceHandle() |
|
| 342 | |||
| 343 | /** |
||
| 344 | * Sets the content of the part to the passed string (effectively creates |
||
| 345 | * a php://temp stream with the passed content and calls |
||
| 346 | * attachContentResourceHandle with the opened stream). |
||
| 347 | * |
||
| 348 | * @param string $string |
||
| 349 | */ |
||
| 350 | 9 | public function setContent($string) |
|
| 357 | |||
| 358 | /** |
||
| 359 | * Returns the resource stream handle for the part's content or null if not |
||
| 360 | * set. rewind() is called on the stream before returning it. |
||
| 361 | * |
||
| 362 | * The resource is automatically closed by MimePart's destructor and should |
||
| 363 | * not be closed otherwise. |
||
| 364 | * |
||
| 365 | * @return resource |
||
| 366 | */ |
||
| 367 | 84 | public function getContentResourceHandle() |
|
| 374 | |||
| 375 | /** |
||
| 376 | * Shortcut to reading stream content and assigning it to a string. Returns |
||
| 377 | * null if the part doesn't have a content stream. |
||
| 378 | * |
||
| 379 | * @return string |
||
| 380 | */ |
||
| 381 | 15 | public function getContent() |
|
| 388 | |||
| 389 | /** |
||
| 390 | * Adds a header with the given $name and $value. |
||
| 391 | * |
||
| 392 | * Creates a new \ZBateson\MailMimeParser\Header\AbstractHeader object and |
||
| 393 | * registers it as a header. |
||
| 394 | * |
||
| 395 | * @param string $name |
||
| 396 | * @param string $value |
||
| 397 | */ |
||
| 398 | 86 | public function setRawHeader($name, $value) |
|
| 402 | |||
| 403 | /** |
||
| 404 | * Removes the header with the given name |
||
| 405 | * |
||
| 406 | * @param string $name |
||
| 407 | */ |
||
| 408 | 8 | public function removeHeader($name) |
|
| 412 | |||
| 413 | /** |
||
| 414 | * Returns the AbstractHeader object for the header with the given $name |
||
| 415 | * |
||
| 416 | * Note that mime headers aren't case sensitive. |
||
| 417 | * |
||
| 418 | * @param string $name |
||
| 419 | * @return \ZBateson\MailMimeParser\Header\AbstractHeader |
||
| 420 | */ |
||
| 421 | 88 | public function getHeader($name) |
|
| 428 | |||
| 429 | /** |
||
| 430 | * Returns the string value for the header with the given $name. |
||
| 431 | * |
||
| 432 | * Note that mime headers aren't case sensitive. |
||
| 433 | * |
||
| 434 | * @param string $name |
||
| 435 | * @param string $defaultValue |
||
| 436 | * @return string |
||
| 437 | */ |
||
| 438 | 85 | public function getHeaderValue($name, $defaultValue = null) |
|
| 446 | |||
| 447 | /** |
||
| 448 | * Returns the full array of headers for this part. |
||
| 449 | * |
||
| 450 | * @return \ZBateson\MailMimeParser\Header\AbstractHeader[] |
||
| 451 | */ |
||
| 452 | 81 | public function getHeaders() |
|
| 456 | |||
| 457 | /** |
||
| 458 | * Returns a parameter of the header $header, given the parameter named |
||
| 459 | * $param. |
||
| 460 | * |
||
| 461 | * Only headers of type |
||
| 462 | * \ZBateson\MailMimeParser\Header\ParameterHeader have parameters. |
||
| 463 | * Content-Type and Content-Disposition are examples of headers with |
||
| 464 | * parameters. "Charset" is a common parameter of Content-Type. |
||
| 465 | * |
||
| 466 | * @param string $header |
||
| 467 | * @param string $param |
||
| 468 | * @param string $defaultValue |
||
| 469 | * @return string |
||
| 470 | */ |
||
| 471 | 85 | public function getHeaderParameter($header, $param, $defaultValue = null) |
|
| 479 | |||
| 480 | /** |
||
| 481 | * Sets the parent part. |
||
| 482 | * |
||
| 483 | * @param \ZBateson\MailMimeParser\Message\MimePart $part |
||
| 484 | */ |
||
| 485 | 82 | public function setParent(MimePart $part) |
|
| 489 | |||
| 490 | /** |
||
| 491 | * Returns this part's parent. |
||
| 492 | * |
||
| 493 | * @return \ZBateson\MailMimeParser\Message\MimePart |
||
| 494 | */ |
||
| 495 | 84 | public function getParent() |
|
| 499 | } |
||
| 500 |
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.