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 Requests_Transport_cURL 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 Requests_Transport_cURL, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 15 | /** |
||
| 16 | * cURL HTTP transport |
||
| 17 | * |
||
| 18 | * @package Rmccue\Requests |
||
| 19 | * @subpackage Transport |
||
| 20 | */ |
||
| 21 | class cURL implements Transport { |
||
| 22 | const CURL_7_10_5 = 0x070A05; |
||
| 23 | const CURL_7_16_2 = 0x071002; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * Raw HTTP data |
||
| 27 | * |
||
| 28 | * @var string |
||
| 29 | */ |
||
| 30 | public $headers = ''; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Raw body data |
||
| 34 | * |
||
| 35 | * @var string |
||
| 36 | */ |
||
| 37 | public $response_data = ''; |
||
| 38 | |||
| 39 | /** |
||
| 40 | * Information on the current request |
||
| 41 | * |
||
| 42 | * @var array cURL information array, see {@see https://secure.php.net/curl_getinfo} |
||
| 43 | */ |
||
| 44 | public $info; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Version string |
||
| 48 | * |
||
| 49 | * @var long |
||
| 50 | */ |
||
| 51 | public $version; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * cURL handle |
||
| 55 | * |
||
| 56 | * @var resource |
||
| 57 | */ |
||
| 58 | protected $handle; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Hook dispatcher instance |
||
| 62 | * |
||
| 63 | * @var Rmccue\Requests\Hooks |
||
| 64 | */ |
||
| 65 | protected $hooks; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Have we finished the headers yet? |
||
| 69 | * |
||
| 70 | * @var boolean |
||
| 71 | */ |
||
| 72 | protected $done_headers = false; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * If streaming to a file, keep the file pointer |
||
| 76 | * |
||
| 77 | * @var resource |
||
| 78 | */ |
||
| 79 | protected $stream_handle; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * How many bytes are in the response body? |
||
| 83 | * |
||
| 84 | * @var int |
||
| 85 | */ |
||
| 86 | protected $response_bytes; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * What's the maximum number of bytes we should keep? |
||
| 90 | * |
||
| 91 | * @var int|bool Byte count, or false if no limit. |
||
| 92 | */ |
||
| 93 | protected $response_byte_limit; |
||
| 94 | |||
| 95 | /** |
||
| 96 | * Constructor |
||
| 97 | */ |
||
| 98 | public function __construct() { |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Destructor |
||
| 118 | */ |
||
| 119 | public function __destruct() { |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Perform a request |
||
| 127 | * |
||
| 128 | * @throws Rmccue\Requests\Exception On a cURL error (`curlerror`) |
||
| 129 | * |
||
| 130 | * @param string $url URL to request |
||
| 131 | * @param array $headers Associative array of request headers |
||
| 132 | * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD |
||
| 133 | * @param array $options Request options, see {@see Requests::response()} for documentation |
||
| 134 | * @return string Raw HTTP result |
||
| 135 | */ |
||
| 136 | public function request($url, $headers = array(), $data = array(), $options = array()) { |
||
| 192 | |||
| 193 | /** |
||
| 194 | * Send multiple requests simultaneously |
||
| 195 | * |
||
| 196 | * @param array $requests Request data |
||
| 197 | * @param array $options Global options |
||
| 198 | * @return array Array of Rmccue\Requests\Response objects (may contain Rmccue\Requests\Exception or string responses as well) |
||
| 199 | */ |
||
| 200 | public function request_multiple($requests, $options) { |
||
| 279 | |||
| 280 | /** |
||
| 281 | * Get the cURL handle for use in a multi-request |
||
| 282 | * |
||
| 283 | * @param string $url URL to request |
||
| 284 | * @param array $headers Associative array of request headers |
||
| 285 | * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD |
||
| 286 | * @param array $options Request options, see {@see Requests::response()} for documentation |
||
| 287 | * @return resource Subrequest's cURL handle |
||
| 288 | */ |
||
| 289 | public function &get_subrequest_handle($url, $headers, $data, $options) { |
||
| 306 | |||
| 307 | /** |
||
| 308 | * Setup the cURL handle for the given data |
||
| 309 | * |
||
| 310 | * @param string $url URL to request |
||
| 311 | * @param array $headers Associative array of request headers |
||
| 312 | * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD |
||
| 313 | * @param array $options Request options, see {@see Requests::response()} for documentation |
||
| 314 | */ |
||
| 315 | protected function setup_handle($url, $headers, $data, $options) { |
||
| 400 | |||
| 401 | /** |
||
| 402 | * Process a response |
||
| 403 | * |
||
| 404 | * @param string $response Response data from the body |
||
| 405 | * @param array $options Request options |
||
| 406 | * @return string HTTP response data including headers |
||
| 407 | */ |
||
| 408 | public function process_response($response, $options) { |
||
| 435 | |||
| 436 | /** |
||
| 437 | * Collect the headers as they are received |
||
| 438 | * |
||
| 439 | * @param resource $handle cURL resource |
||
| 440 | * @param string $headers Header string |
||
| 441 | * @return integer Length of provided header |
||
| 442 | */ |
||
| 443 | public function stream_headers($handle, $headers) { |
||
| 458 | |||
| 459 | /** |
||
| 460 | * Collect data as it's received |
||
| 461 | * |
||
| 462 | * @since 1.6.1 |
||
| 463 | * |
||
| 464 | * @param resource $handle cURL resource |
||
| 465 | * @param string $data Body data |
||
| 466 | * @return integer Length of provided data |
||
| 467 | */ |
||
| 468 | public function stream_body($handle, $data) { |
||
| 496 | |||
| 497 | /** |
||
| 498 | * Format a URL given GET data |
||
| 499 | * |
||
| 500 | * @param string $url |
||
| 501 | * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query} |
||
| 502 | * @return string URL with data |
||
| 503 | */ |
||
| 504 | protected static function format_get($url, $data) { |
||
| 526 | |||
| 527 | /** |
||
| 528 | * Whether this transport is valid |
||
| 529 | * |
||
| 530 | * @codeCoverageIgnore |
||
| 531 | * @return boolean True if the transport is valid, false otherwise. |
||
| 532 | */ |
||
| 533 | public static function test($capabilities = array()) { |
||
| 534 | if (!function_exists('curl_init') || !function_exists('curl_exec')) { |
||
| 535 | return false; |
||
| 536 | } |
||
| 537 | |||
| 538 | // If needed, check that our installed curl version supports SSL |
||
| 539 | if (isset($capabilities['ssl']) && $capabilities['ssl']) { |
||
| 540 | $curl_version = curl_version(); |
||
| 541 | if (!(CURL_VERSION_SSL & $curl_version['features'])) { |
||
| 542 | return false; |
||
| 543 | } |
||
| 549 |
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.