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 Part 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 Part, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 11 | class Part implements \RecursiveIterator |
||
| 12 | { |
||
| 13 | const TYPE_TEXT = 'text'; |
||
| 14 | const TYPE_MULTIPART = 'multipart'; |
||
| 15 | const TYPE_MESSAGE = 'message'; |
||
| 16 | const TYPE_APPLICATION = 'application'; |
||
| 17 | const TYPE_AUDIO = 'audio'; |
||
| 18 | const TYPE_IMAGE = 'image'; |
||
| 19 | const TYPE_VIDEO = 'video'; |
||
| 20 | const TYPE_OTHER = 'other'; |
||
| 21 | const TYPE_UNKNOWN = 'unknown'; |
||
| 22 | |||
| 23 | const ENCODING_7BIT = '7bit'; |
||
| 24 | const ENCODING_8BIT = '8bit'; |
||
| 25 | const ENCODING_BINARY = 'binary'; |
||
| 26 | const ENCODING_BASE64 = 'base64'; |
||
| 27 | const ENCODING_QUOTED_PRINTABLE = 'quoted-printable'; |
||
| 28 | const ENCODING_UNKNOWN = 'unknown'; |
||
| 29 | |||
| 30 | const SUBTYPE_TEXT = 'TEXT'; |
||
| 31 | const SUBTYPE_HTML = 'HTML'; |
||
| 32 | |||
| 33 | protected $typesMap = array( |
||
| 34 | 0 => self::TYPE_TEXT, |
||
| 35 | 1 => self::TYPE_MULTIPART, |
||
| 36 | 2 => self::TYPE_MESSAGE, |
||
| 37 | 3 => self::TYPE_APPLICATION, |
||
| 38 | 4 => self::TYPE_AUDIO, |
||
| 39 | 5 => self::TYPE_IMAGE, |
||
| 40 | 6 => self::TYPE_VIDEO, |
||
| 41 | 7 => self::TYPE_OTHER |
||
| 42 | ); |
||
| 43 | |||
| 44 | protected $encodingsMap = array( |
||
| 45 | 0 => self::ENCODING_7BIT, |
||
| 46 | 1 => self::ENCODING_8BIT, |
||
| 47 | 2 => self::ENCODING_BINARY, |
||
| 48 | 3 => self::ENCODING_BASE64, |
||
| 49 | 4 => self::ENCODING_QUOTED_PRINTABLE, |
||
| 50 | 5 => self::ENCODING_UNKNOWN |
||
| 51 | ); |
||
| 52 | |||
| 53 | protected $type; |
||
| 54 | |||
| 55 | protected $subtype; |
||
| 56 | |||
| 57 | protected $encoding; |
||
| 58 | |||
| 59 | protected $bytes; |
||
| 60 | |||
| 61 | protected $lines; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @var Parameters |
||
| 65 | */ |
||
| 66 | protected $parameters; |
||
| 67 | |||
| 68 | protected $stream; |
||
| 69 | |||
| 70 | protected $messageNumber; |
||
| 71 | |||
| 72 | protected $partNumber; |
||
| 73 | |||
| 74 | protected $structure; |
||
| 75 | |||
| 76 | protected $content; |
||
| 77 | |||
| 78 | protected $decodedContent; |
||
| 79 | |||
| 80 | protected $parts = array(); |
||
| 81 | |||
| 82 | protected $key = 0; |
||
| 83 | |||
| 84 | protected $disposition; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Constructor |
||
| 88 | * |
||
| 89 | * @param resource $stream IMAP stream |
||
| 90 | * @param int $messageNumber Message number |
||
| 91 | * @param int $partNumber Part number (optional) |
||
| 92 | * @param \stdClass $structure Part structure |
||
| 93 | */ |
||
| 94 | public function __construct( |
||
| 106 | |||
| 107 | public function getCharset() |
||
| 111 | |||
| 112 | public function getType() |
||
| 116 | |||
| 117 | public function getSubtype() |
||
| 121 | |||
| 122 | public function getEncoding() |
||
| 126 | |||
| 127 | public function getBytes() |
||
| 131 | |||
| 132 | public function getLines() |
||
| 136 | |||
| 137 | public function getParameters() |
||
| 141 | |||
| 142 | /** |
||
| 143 | * Get raw part content |
||
| 144 | * |
||
| 145 | * @return string |
||
| 146 | */ |
||
| 147 | public function getContent($keepUnseen = false) |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Get decoded part content |
||
| 158 | * |
||
| 159 | * @return string |
||
| 160 | */ |
||
| 161 | public function getDecodedContent($keepUnseen = false) |
||
| 194 | |||
| 195 | public function getStructure() |
||
| 199 | |||
| 200 | protected function fetchStructure($partNumber = null) |
||
| 212 | |||
| 213 | protected function parseStructure(\stdClass $structure) { |
||
| 262 | |||
| 263 | /** |
||
| 264 | * Get an array of all parts for this message |
||
| 265 | * |
||
| 266 | * @return self[] |
||
| 267 | */ |
||
| 268 | public function getParts() |
||
| 272 | |||
| 273 | public function current() |
||
| 277 | |||
| 278 | public function getChildren() |
||
| 282 | |||
| 283 | public function hasChildren() |
||
| 287 | |||
| 288 | public function key() |
||
| 292 | |||
| 293 | public function next() |
||
| 297 | |||
| 298 | public function rewind() |
||
| 302 | |||
| 303 | public function valid() |
||
| 307 | |||
| 308 | public function getDisposition() |
||
| 312 | |||
| 313 | /** |
||
| 314 | * Get raw message content |
||
| 315 | * |
||
| 316 | * @param bool $keepUnseen Whether to keep the message unseen. |
||
| 317 | * Default behaviour is set set the seen flag when |
||
| 318 | * getting content. |
||
| 319 | * |
||
| 320 | * @return string |
||
| 321 | */ |
||
| 322 | protected function doGetContent($keepUnseen = false) |
||
| 331 | |||
| 332 | private function isAttachment($part) { |
||
| 366 | } |
||
| 367 |
It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.
We recommend to add an additional type check (or disallow null for the parameter):