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 UserInformation 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 UserInformation, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class UserInformation |
||
29 | { |
||
30 | /** 男性 */ |
||
31 | const SEX_MALE = '男'; |
||
32 | /** 女性 */ |
||
33 | const SEX_FEMALE = '女'; |
||
34 | /** 不明/その他の性 */ |
||
35 | const SEX_OTHERS = null; |
||
36 | |||
37 | /** 血液型: A */ |
||
38 | const BLOOD_TYPE_A = 'A'; |
||
39 | /** 血液型: B */ |
||
40 | const BLOOD_TYPE_B = 'B'; |
||
41 | /** 血液型: O */ |
||
42 | const BLOOD_TYPE_O = 'O'; |
||
43 | /** 血液型: AB */ |
||
44 | const BLOOD_TYPE_AB = 'AB'; |
||
45 | /** 血液型: 不明 */ |
||
46 | const BLOOD_TYPE_UNKNOWN = null; |
||
47 | |||
48 | /** 星座: 牡羊座 */ |
||
49 | const CONSTELLATION_ARIES = '牡羊座'; |
||
50 | /** 星座: 牡牛座 */ |
||
51 | const CONSTELLATION_TAURUS = '牡牛座'; |
||
52 | /** 星座: 双子座 */ |
||
53 | const CONSTELLATION_GEMINI = '双子座'; |
||
54 | /** 星座: 蟹座 */ |
||
55 | const CONSTELLATION_CANCER = '蟹座'; |
||
56 | /** 星座: 獅子座 */ |
||
57 | const CONSTELLATION_LEO = '獅子座'; |
||
58 | /** 星座: 乙女座 */ |
||
59 | const CONSTELLATION_VIRGO = '乙女座'; |
||
60 | /** 星座: 天秤座 */ |
||
61 | const CONSTELLATION_LIBRA = '天秤座'; |
||
62 | /** 星座: 蠍座 */ |
||
63 | const CONSTELLATION_SCORPIUS = '蠍座'; |
||
64 | /** 星座: 射手座 */ |
||
65 | const CONSTELLATION_SAGITTARIUS = '射手座'; |
||
66 | /** 星座: 山羊座 */ |
||
67 | const CONSTELLATION_CAPRICONUS = '山羊座'; |
||
68 | /** 星座: 水瓶座 */ |
||
69 | const CONSTELLATION_AQUARIUS = '水瓶座'; |
||
70 | /** 星座: 魚座 */ |
||
71 | const CONSTELLATION_PISCES = '魚座'; |
||
72 | |||
73 | /** @internal 送信パラメータ */ |
||
74 | private $parameters = [ |
||
75 | 'nickname' => null, // ユーザのニックネーム |
||
76 | 'nickname_y' => null, // ユーザのニックネームの読み(カナ) |
||
77 | 'sex' => self::SEX_OTHERS, // ユーザの性別 |
||
78 | 'bloodtype' => self::BLOOD_TYPE_UNKNOWN, // ユーザの血液型 |
||
79 | 'birthdateY' => null, // ユーザの誕生日(Y) |
||
80 | 'birthdateM' => null, // ユーザの誕生日(M) |
||
81 | 'birthdateD' => null, // ユーザの誕生日(D) |
||
82 | 'age' => null, // ユーザの年齢 |
||
83 | 'constellations' => null, // ユーザの星座 |
||
84 | 'place' => null, // ユーザの場所 |
||
85 | ]; |
||
86 | |||
87 | /** |
||
88 | * @internal 場所情報として有効な地点の一覧 |
||
89 | * @see setPlace() |
||
90 | * @see getPlace() |
||
91 | */ |
||
92 | private static $validPlaces = [ |
||
93 | '稚内', '旭川', '留萌', '網走', '北見', '紋別', '根室', '釧路', '帯広', '室蘭', |
||
94 | '浦河', '札幌', '岩見沢', '倶知安', '函館', '江差', '青森', '弘前', '深浦', |
||
95 | 'むつ', '八戸', '秋田', '横手', '鷹巣', '盛岡', '二戸', '一関', '宮古', |
||
96 | '大船渡', '山形', '米沢', '酒田', '新庄', '仙台', '古川', '石巻', '白石', |
||
97 | '福島', '郡山', '白河', '小名浜', '相馬', '若松', '田島', '宇都宮', '大田原', |
||
98 | '水戸', '土浦', '前橋', 'みなかみ', 'さいたま', '熊谷', '秩父', '東京', '大島', |
||
99 | '八丈島', '父島', '千葉', '銚子', '館山', '横浜', '小田原', '甲府', '河口湖', |
||
100 | '長野', '松本', '諏訪', '軽井沢', '飯田', '静岡', '網代', '石廊崎', '三島', |
||
101 | '浜松', '御前崎', '新潟', '津川', '長岡', '湯沢', '高田', '相川', '富山', |
||
102 | '伏木', '岐阜', '高山', '名古屋', '豊橋', '福井', '大野', '敦賀', '金沢', |
||
103 | '輪島', '大津', '彦根', '津', '上野', '四日市', '尾鷲', '京都', '舞鶴', '奈良', |
||
104 | '風屋', '和歌山', '潮岬', '大阪', '神戸', '姫路', '洲本', '豊岡', '鳥取', |
||
105 | '米子', '岡山', '津山', '松江', '浜田', '西郷', '広島', '呉', '福山', '庄原', |
||
106 | '下関', '山口', '柳井', '萩', '高松', '徳島', '池田', '日和佐', '松山', |
||
107 | '新居浜', '宇和島', '高知', '室戸岬', '清水', '福岡', '八幡', '飯塚', '久留米', |
||
108 | '佐賀', '伊万里', '長崎', '佐世保', '厳原', '福江', '大分', '中津', '日田', |
||
109 | '佐伯', '熊本', '阿蘇乙姫', '牛深', '人吉', '宮崎', '油津', '延岡', '都城', |
||
110 | '高千穂', '鹿児島', '阿久根', '枕崎', '鹿屋', '種子島', '名瀬', '沖永良部', |
||
111 | '那覇', '名護', '久米島', '南大東島', '宮古島', '石垣島','与那国島', '海外' |
||
112 | ]; |
||
113 | |||
114 | /** |
||
115 | * マジックメソッド __toString |
||
116 | * |
||
117 | * デバッグ等で表示する際に中身がわかるように JSON で返すだけで、 |
||
118 | * 表現そのものに意味はないし依存してはならない |
||
119 | * |
||
120 | * @return string |
||
121 | */ |
||
122 | public function __toString() |
||
126 | |||
127 | /** |
||
128 | * マジックメソッド __get |
||
129 | * |
||
130 | * @param string $key プロパティ取得用のキー |
||
131 | * @return string キーに対応する値 |
||
132 | * |
||
133 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
134 | */ |
||
135 | public function __get($key) |
||
160 | |||
161 | /** |
||
162 | * マジックメソッド __set |
||
163 | * |
||
164 | * @param string $key プロパティ設定用のキー |
||
165 | * @param string $value 設定する値 |
||
166 | * |
||
167 | * @throws InvalidArgumentException 対応するキーが存在しない時 |
||
168 | * @throws DomainError 設定する値が異常な時 |
||
169 | * |
||
170 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
171 | */ |
||
172 | public function __set($key, $value) |
||
199 | |||
200 | /** |
||
201 | * ユーザのニックネームを取得 |
||
202 | * |
||
203 | * @return string |
||
204 | */ |
||
205 | public function getNickname() |
||
209 | |||
210 | /** |
||
211 | * ユーザのニックネーム(読み)を取得 |
||
212 | * |
||
213 | * @return string |
||
214 | */ |
||
215 | public function getNicknameY() |
||
219 | |||
220 | /** |
||
221 | * ユーザの性別を取得 |
||
222 | * |
||
223 | * @return string |
||
224 | */ |
||
225 | public function getSex() |
||
229 | |||
230 | /** |
||
231 | * ユーザの血液型を取得 |
||
232 | * |
||
233 | * @return string |
||
234 | */ |
||
235 | public function getBloodType() |
||
239 | |||
240 | /** |
||
241 | * ユーザの生年月日(年)を取得 |
||
242 | * |
||
243 | * @return string |
||
244 | */ |
||
245 | public function getBirthdateY() |
||
249 | |||
250 | /** |
||
251 | * ユーザの生年月日(月)を取得 |
||
252 | * |
||
253 | * @return string |
||
254 | */ |
||
255 | public function getBirthdateM() |
||
259 | |||
260 | /** |
||
261 | * ユーザの生年月日(日)を取得 |
||
262 | * |
||
263 | * @return string |
||
264 | */ |
||
265 | public function getBirthdateD() |
||
269 | |||
270 | /** |
||
271 | * ユーザの年齢を取得 |
||
272 | * |
||
273 | * @return string |
||
274 | */ |
||
275 | public function getAge() |
||
279 | |||
280 | /** |
||
281 | * ユーザの星座を取得 |
||
282 | * |
||
283 | * @return string |
||
284 | */ |
||
285 | public function getConstellations() |
||
289 | |||
290 | /** |
||
291 | * ユーザの場所を取得 |
||
292 | * |
||
293 | * @return string |
||
294 | */ |
||
295 | public function getPlace() |
||
299 | |||
300 | /** |
||
301 | * ユーザのニックネームを設定する |
||
302 | * |
||
303 | * @param string $value ニックネーム(最大10文字) |
||
304 | * @return self |
||
305 | * @throws DomainError |
||
306 | */ |
||
307 | public function setNickname($value) |
||
313 | |||
314 | /** |
||
315 | * ユーザのニックネーム(読み)を設定する |
||
316 | * |
||
317 | * @param string $value ニックネームの読み(最大20文字) |
||
318 | * @return self |
||
319 | * @throws DomainError |
||
320 | */ |
||
321 | public function setNicknameY($value) |
||
331 | |||
332 | /** |
||
333 | * ユーザの性別を設定する |
||
334 | * |
||
335 | * @param string $value ユーザの性別 SEX_MALE | SEX_FEMALE | SEX_OTHERS |
||
336 | * @return self |
||
337 | * @throws DomainError |
||
338 | */ |
||
339 | View Code Duplication | public function setSex($value) |
|
349 | |||
350 | /** |
||
351 | * ユーザの血液型を設定する |
||
352 | * |
||
353 | * @param string $value ユーザの血液型 BLOOD_TYPE_* |
||
354 | * @return self |
||
355 | * @throws DomainError |
||
356 | */ |
||
357 | public function setBloodType($value) |
||
369 | |||
370 | /** |
||
371 | * ユーザの生年月日(年)を設定する |
||
372 | * |
||
373 | * @param int $value ユーザの生年月日(年) |
||
374 | * @return self |
||
375 | * @throws DomainError |
||
376 | */ |
||
377 | public function setBirthdateY($value) |
||
389 | |||
390 | /** |
||
391 | * ユーザの生年月日(月)を設定する |
||
392 | * |
||
393 | * @param int $value ユーザの生年月日(月) |
||
394 | * @return self |
||
395 | * @throws DomainError |
||
396 | */ |
||
397 | View Code Duplication | public function setBirthdateM($value) |
|
407 | |||
408 | /** |
||
409 | * ユーザの生年月日(日)を設定する |
||
410 | * |
||
411 | * @param int $value ユーザの生年月日(日) |
||
412 | * @return self |
||
413 | * @throws DomainError |
||
414 | */ |
||
415 | View Code Duplication | public function setBirthdateD($value) |
|
425 | |||
426 | /** |
||
427 | * ユーザの年齢を設定する |
||
428 | * |
||
429 | * @param int $value ユーザの年齢 |
||
430 | * @return self |
||
431 | * @throws DomainError |
||
432 | */ |
||
433 | View Code Duplication | public function setAge($value) |
|
443 | |||
444 | /** |
||
445 | * ユーザの星座を設定する |
||
446 | * |
||
447 | * @param string $value ユーザの星座 CONSTELLATION_* |
||
448 | * @return self |
||
449 | * @throws DomainError |
||
450 | */ |
||
451 | public function setConstellations($value) |
||
473 | |||
474 | /** |
||
475 | * ユーザの場所を設定する |
||
476 | * |
||
477 | * @param string $value ユーザの場所 one of $validPlaces |
||
478 | * @return self |
||
479 | * @throws DomainError |
||
480 | */ |
||
481 | public function setPlace($value) |
||
490 | |||
491 | /** |
||
492 | * 送信用のパラメータ配列を作成して取得する |
||
493 | * |
||
494 | * @return array |
||
495 | */ |
||
496 | public function makeParameter() |
||
506 | |||
507 | /** |
||
508 | * クラス名(FQCN)を取得 |
||
509 | * |
||
510 | * return string |
||
511 | */ |
||
512 | public static function className() |
||
516 | } |
||
517 |
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.