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 Google_IO_Abstract 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 Google_IO_Abstract, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | abstract class Google_IO_Abstract |
||
27 | { |
||
28 | const UNKNOWN_CODE = 0; |
||
29 | const FORM_URLENCODED = 'application/x-www-form-urlencoded'; |
||
30 | private static $CONNECTION_ESTABLISHED_HEADERS = array( |
||
31 | "HTTP/1.0 200 Connection established\r\n\r\n", |
||
32 | "HTTP/1.1 200 Connection established\r\n\r\n", |
||
33 | ); |
||
34 | private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null); |
||
35 | private static $HOP_BY_HOP = array( |
||
36 | 'connection' => true, |
||
37 | 'keep-alive' => true, |
||
38 | 'proxy-authenticate' => true, |
||
39 | 'proxy-authorization' => true, |
||
40 | 'te' => true, |
||
41 | 'trailers' => true, |
||
42 | 'transfer-encoding' => true, |
||
43 | 'upgrade' => true |
||
44 | ); |
||
45 | |||
46 | |||
47 | /** @var Google_Client */ |
||
48 | protected $client; |
||
49 | |||
50 | public function __construct(Google_Client $client) |
||
58 | |||
59 | /** |
||
60 | * Executes a Google_Http_Request |
||
61 | * @param Google_Http_Request $request the http request to be executed |
||
62 | * @return array containing response headers, body, and http code |
||
63 | * @throws Google_IO_Exception on curl or IO error |
||
64 | */ |
||
65 | abstract public function executeRequest(Google_Http_Request $request); |
||
66 | |||
67 | /** |
||
68 | * Set options that update the transport implementation's behavior. |
||
69 | * @param $options |
||
70 | */ |
||
71 | abstract public function setOptions($options); |
||
72 | |||
73 | /** |
||
74 | * Set the maximum request time in seconds. |
||
75 | * @param $timeout in seconds |
||
76 | */ |
||
77 | abstract public function setTimeout($timeout); |
||
78 | |||
79 | /** |
||
80 | * Get the maximum request time in seconds. |
||
81 | * @return timeout in seconds |
||
82 | */ |
||
83 | abstract public function getTimeout(); |
||
84 | |||
85 | /** |
||
86 | * Test for the presence of a cURL header processing bug |
||
87 | * |
||
88 | * The cURL bug was present in versions prior to 7.30.0 and caused the header |
||
89 | * length to be miscalculated when a "Connection established" header added by |
||
90 | * some proxies was present. |
||
91 | * |
||
92 | * @return boolean |
||
93 | */ |
||
94 | abstract protected function needsQuirk(); |
||
95 | |||
96 | /** |
||
97 | * @visible for testing. |
||
98 | * Cache the response to an HTTP request if it is cacheable. |
||
99 | * @param Google_Http_Request $request |
||
100 | * @return bool Returns true if the insertion was successful. |
||
101 | * Otherwise, return false. |
||
102 | */ |
||
103 | View Code Duplication | public function setCachedRequest(Google_Http_Request $request) |
|
113 | |||
114 | /** |
||
115 | * Execute an HTTP Request |
||
116 | * |
||
117 | * @param Google_Http_Request $request the http request to be executed |
||
118 | * @return Google_Http_Request http request with the response http code, |
||
119 | * response headers and response body filled in |
||
120 | * @throws Google_IO_Exception on curl or IO error |
||
121 | */ |
||
122 | public function makeRequest(Google_Http_Request $request) |
||
156 | |||
157 | /** |
||
158 | * @visible for testing. |
||
159 | * @param Google_Http_Request $request |
||
160 | * @return Google_Http_Request|bool Returns the cached object or |
||
161 | * false if the operation was unsuccessful. |
||
162 | */ |
||
163 | View Code Duplication | public function getCachedRequest(Google_Http_Request $request) |
|
171 | |||
172 | /** |
||
173 | * @visible for testing |
||
174 | * Process an http request that contains an enclosed entity. |
||
175 | * @param Google_Http_Request $request |
||
176 | * @return Google_Http_Request Processed request with the enclosed entity. |
||
177 | */ |
||
178 | public function processEntityRequest(Google_Http_Request $request) |
||
203 | |||
204 | /** |
||
205 | * Check if an already cached request must be revalidated, and if so update |
||
206 | * the request with the correct ETag headers. |
||
207 | * @param Google_Http_Request $cached A previously cached response. |
||
208 | * @param Google_Http_Request $request The outbound request. |
||
209 | * return bool If the cached object needs to be revalidated, false if it is |
||
210 | * still current and can be re-used. |
||
211 | */ |
||
212 | protected function checkMustRevalidateCachedRequest($cached, $request) |
||
230 | |||
231 | /** |
||
232 | * Update a cached request, using the headers from the last response. |
||
233 | * @param Google_Http_Request $cached A previously cached response. |
||
234 | * @param mixed Associative array of response headers from the last request. |
||
235 | */ |
||
236 | protected function updateCachedRequest($cached, $responseHeaders) |
||
252 | |||
253 | /** |
||
254 | * Used by the IO lib and also the batch processing. |
||
255 | * |
||
256 | * @param $respData |
||
257 | * @param $headerSize |
||
258 | * @return array |
||
259 | */ |
||
260 | public function parseHttpResponse($respData, $headerSize) |
||
290 | |||
291 | /** |
||
292 | * Parse out headers from raw headers |
||
293 | * @param rawHeaders array or string |
||
294 | * @return array |
||
295 | */ |
||
296 | public function getHttpResponseHeaders($rawHeaders) |
||
304 | |||
305 | private function parseStringHeaders($rawHeaders) |
||
322 | |||
323 | private function parseArrayHeaders($rawHeaders) |
||
339 | } |
||
340 |
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.