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 Uri 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 Uri, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Uri implements UriInterface |
||
17 | { |
||
18 | /** |
||
19 | * @var string |
||
20 | */ |
||
21 | protected $_uri; |
||
22 | |||
23 | /** |
||
24 | * @var string The URI's scheme |
||
25 | */ |
||
26 | protected $_scheme = 'blob'; // User-Agent |
||
27 | |||
28 | /** |
||
29 | * @var string The URI's query |
||
30 | */ |
||
31 | protected $_query; |
||
32 | |||
33 | /** |
||
34 | * @var string The URI's path |
||
35 | */ |
||
36 | protected $_path; |
||
37 | |||
38 | /** |
||
39 | * @var string The URI's fragment |
||
40 | */ |
||
41 | protected $_fragment; |
||
42 | |||
43 | /** |
||
44 | * @var string The URI's host |
||
45 | */ |
||
46 | protected $_host; |
||
47 | |||
48 | /** |
||
49 | * @var string The URI's port |
||
50 | */ |
||
51 | protected $_port; |
||
52 | |||
53 | /** |
||
54 | * @var string The URI's specified user |
||
55 | */ |
||
56 | protected $_username; |
||
57 | |||
58 | /** |
||
59 | * @var string The URI's specified password |
||
60 | */ |
||
61 | protected $_password; |
||
62 | |||
63 | |||
64 | /** |
||
65 | * Constructs a new URI |
||
66 | * |
||
67 | * @param string $uri The URI |
||
68 | * @return boolean true if success |
||
|
|||
69 | */ |
||
70 | public function __construct($uri = null) |
||
82 | |||
83 | /** |
||
84 | * Return the URI's scheme. |
||
85 | * |
||
86 | * @return string |
||
87 | */ |
||
88 | public function getScheme() |
||
96 | |||
97 | /** |
||
98 | * Returns the user authority in the "[user-info@]host[:port]" format. |
||
99 | * |
||
100 | * @param type name description |
||
101 | * @return type description |
||
102 | */ |
||
103 | public function getAuthority() |
||
112 | |||
113 | /** |
||
114 | * Returns user info in the "username[:password]" format. |
||
115 | * |
||
116 | * @return string |
||
117 | */ |
||
118 | public function getUserInfo() |
||
128 | |||
129 | /** |
||
130 | * Retrieves the username (user=) specified in the URI. |
||
131 | * |
||
132 | * @return string |
||
133 | */ |
||
134 | View Code Duplication | public function getUsername() |
|
143 | |||
144 | /** |
||
145 | * Retrieves the password specified in the URI. |
||
146 | * |
||
147 | * @return string |
||
148 | */ |
||
149 | View Code Duplication | public function getPassword() |
|
158 | |||
159 | /** |
||
160 | * Retrieves the URI's host. |
||
161 | * |
||
162 | * @return string |
||
163 | */ |
||
164 | public function getHost() |
||
170 | |||
171 | /** |
||
172 | * Retrieves the URI's port. |
||
173 | * |
||
174 | * @return string |
||
175 | */ |
||
176 | public function getPort() |
||
182 | |||
183 | /** |
||
184 | * Returns the URI's path. |
||
185 | * |
||
186 | * @return string |
||
187 | */ |
||
188 | public function getPath() |
||
192 | |||
193 | /** |
||
194 | * Sets the URI's path. |
||
195 | * |
||
196 | * @return void |
||
197 | */ |
||
198 | protected function setPath() |
||
208 | |||
209 | /** |
||
210 | * Retrieve the query string of the URI. |
||
211 | * |
||
212 | * If no query string is present, this method MUST return an empty string. |
||
213 | * |
||
214 | * The leading "?" character is not part of the query and MUST NOT be |
||
215 | * added. |
||
216 | * |
||
217 | * The value returned MUST be percent-encoded, but MUST NOT double-encode |
||
218 | * any characters. To determine what characters to encode, please refer to |
||
219 | * RFC 3986, Sections 2 and 3.4. |
||
220 | * |
||
221 | * As an example, if a value in a key/value pair of the query string should |
||
222 | * include an ampersand ("&") not intended as a delimiter between values, |
||
223 | * that value MUST be passed in encoded form (e.g., "%26") to the instance. |
||
224 | * |
||
225 | * @see https://tools.ietf.org/html/rfc3986#section-2 |
||
226 | * @see https://tools.ietf.org/html/rfc3986#section-3.4 |
||
227 | * @return string The URI query string. |
||
228 | */ |
||
229 | public function getQuery() |
||
246 | |||
247 | /** |
||
248 | * Retrieves the URI's fragment. |
||
249 | * |
||
250 | * @return string |
||
251 | */ |
||
252 | public function getFragment() |
||
256 | |||
257 | protected function setFragment($fragment = null) |
||
263 | |||
264 | /** |
||
265 | * Return an instance with the specified scheme. |
||
266 | * |
||
267 | * This method MUST retain the state of the current instance, and return |
||
268 | * an instance that contains the specified scheme. |
||
269 | * |
||
270 | * Implementations MUST support the schemes "http" and "https" case |
||
271 | * insensitively, and MAY accommodate other schemes if required. |
||
272 | * |
||
273 | * An empty scheme is equivalent to removing the scheme. |
||
274 | * |
||
275 | * @param string $scheme The scheme to use with the new instance. |
||
276 | * @return static A new instance with the specified scheme. |
||
277 | * @throws \InvalidArgumentException for invalid or unsupported schemes. |
||
278 | */ |
||
279 | public function withScheme($scheme) |
||
286 | |||
287 | protected function setScheme($scheme) |
||
291 | |||
292 | /** |
||
293 | * Return an instance with the specified user information. |
||
294 | * |
||
295 | * This method MUST retain the state of the current instance, and return |
||
296 | * an instance that contains the specified user information. |
||
297 | * |
||
298 | * Password is optional, but the user information MUST include the |
||
299 | * user; an empty string for the user is equivalent to removing user |
||
300 | * information. |
||
301 | * |
||
302 | * @param string $user The user name to use for authority. |
||
303 | * @param null|string $password The password associated with $user. |
||
304 | * @return static A new instance with the specified user information. |
||
305 | */ |
||
306 | public function withUserInfo($user, $password = null) |
||
314 | |||
315 | protected function setUser($user) |
||
319 | |||
320 | protected function setPassword($password) |
||
324 | |||
325 | /** |
||
326 | * Return an instance with the specified host. |
||
327 | * |
||
328 | * This method MUST retain the state of the current instance, and return |
||
329 | * an instance that contains the specified host. |
||
330 | * |
||
331 | * An empty host value is equivalent to removing the host. |
||
332 | * |
||
333 | * @param string $host The hostname to use with the new instance. |
||
334 | * @return static A new instance with the specified host. |
||
335 | * @throws \InvalidArgumentException for invalid hostnames. |
||
336 | */ |
||
337 | public function withHost($host) |
||
344 | |||
345 | /** |
||
346 | * Return an instance with the specified port. |
||
347 | * |
||
348 | * This method MUST retain the state of the current instance, and return |
||
349 | * an instance that contains the specified port. |
||
350 | * |
||
351 | * Implementations MUST raise an exception for ports outside the |
||
352 | * established TCP and UDP port ranges. |
||
353 | * |
||
354 | * A null value provided for the port is equivalent to removing the port |
||
355 | * information. |
||
356 | * |
||
357 | * @param null|int $port The port to use with the new instance; a null value |
||
358 | * removes the port information. |
||
359 | * @return static A new instance with the specified port. |
||
360 | * @throws \InvalidArgumentException for invalid ports. |
||
361 | */ |
||
362 | public function withPort($port) |
||
373 | |||
374 | protected function setPort($port) |
||
378 | |||
379 | /** |
||
380 | * Return an instance with the specified path. |
||
381 | * |
||
382 | * This method MUST retain the state of the current instance, and return |
||
383 | * an instance that contains the specified path. |
||
384 | * |
||
385 | * The path can either be empty or absolute (starting with a slash) or |
||
386 | * rootless (not starting with a slash). Implementations MUST support all |
||
387 | * three syntaxes. |
||
388 | * |
||
389 | * If the path is intended to be domain-relative rather than path relative then |
||
390 | * it must begin with a slash ("/"). Paths not starting with a slash ("/") |
||
391 | * are assumed to be relative to some base path known to the application or |
||
392 | * consumer. |
||
393 | * |
||
394 | * Users can provide both encoded and decoded path characters. |
||
395 | * Implementations ensure the correct encoding as outlined in getPath(). |
||
396 | * |
||
397 | * @param string $path The path to use with the new instance. |
||
398 | * @return static A new instance with the specified path. |
||
399 | * @throws \InvalidArgumentException for invalid paths. |
||
400 | */ |
||
401 | public function withPath($path) |
||
412 | |||
413 | public function withQuery($query) |
||
424 | |||
425 | public function setQuery($query) |
||
433 | |||
434 | public function withFragment($fragment) |
||
441 | |||
442 | public function __toString() |
||
450 | } |
||
451 |
Adding a
@return
annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.