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 Request 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 Request, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
14 | class Request |
||
15 | { |
||
16 | /// @todo: do these need to be public? |
||
17 | public $payload; |
||
18 | public $methodname; |
||
19 | public $params = array(); |
||
20 | public $debug = 0; |
||
21 | public $content_type = 'text/xml'; |
||
22 | |||
23 | // holds data while parsing the response. NB: Not a full Response object |
||
24 | protected $httpResponse = array(); |
||
25 | |||
26 | /** |
||
27 | * @param string $methodName the name of the method to invoke |
||
28 | * @param Value[] $params array of parameters to be passed to the method (NB: Value objects, not plain php values) |
||
29 | */ |
||
30 | 602 | public function __construct($methodName, $params = array()) |
|
31 | { |
||
32 | 602 | $this->methodname = $methodName; |
|
33 | 602 | foreach ($params as $param) { |
|
34 | 429 | $this->addParam($param); |
|
35 | } |
||
36 | 602 | } |
|
37 | |||
38 | 543 | public function xml_header($charsetEncoding = '') |
|
46 | |||
47 | 543 | public function xml_footer() |
|
51 | |||
52 | 543 | public function createPayload($charsetEncoding = '') |
|
53 | { |
||
54 | 543 | if ($charsetEncoding != '') { |
|
55 | 56 | $this->content_type = 'text/xml; charset=' . $charsetEncoding; |
|
56 | } else { |
||
57 | 487 | $this->content_type = 'text/xml'; |
|
58 | } |
||
59 | 543 | $this->payload = $this->xml_header($charsetEncoding); |
|
60 | 543 | $this->payload .= '<methodName>' . Charset::instance()->encodeEntities( |
|
61 | 543 | $this->methodname, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</methodName>\n"; |
|
62 | 543 | $this->payload .= "<params>\n"; |
|
63 | 543 | foreach ($this->params as $p) { |
|
64 | 505 | $this->payload .= "<param>\n" . $p->serialize($charsetEncoding) . |
|
65 | 505 | "</param>\n"; |
|
66 | } |
||
67 | 543 | $this->payload .= "</params>\n"; |
|
68 | 543 | $this->payload .= $this->xml_footer(); |
|
69 | 543 | } |
|
70 | |||
71 | /** |
||
72 | * Gets/sets the xmlrpc method to be invoked. |
||
73 | * |
||
74 | * @param string $methodName the method to be set (leave empty not to set it) |
||
75 | * |
||
76 | * @return string the method that will be invoked |
||
77 | */ |
||
78 | 488 | public function method($methodName = '') |
|
79 | { |
||
80 | 488 | if ($methodName != '') { |
|
81 | $this->methodname = $methodName; |
||
82 | } |
||
83 | |||
84 | 488 | return $this->methodname; |
|
85 | } |
||
86 | |||
87 | /** |
||
88 | * Returns xml representation of the message. XML prologue included. |
||
89 | * |
||
90 | * @param string $charsetEncoding |
||
91 | * |
||
92 | * @return string the xml representation of the message, xml prologue included |
||
93 | */ |
||
94 | 1 | public function serialize($charsetEncoding = '') |
|
100 | |||
101 | /** |
||
102 | * Add a parameter to the list of parameters to be used upon method invocation. |
||
103 | * |
||
104 | * Checks that $params is actually a Value object and not a plain php value. |
||
105 | * |
||
106 | * @param Value $param |
||
107 | * |
||
108 | * @return boolean false on failure |
||
109 | */ |
||
110 | 549 | public function addParam($param) |
|
121 | |||
122 | /** |
||
123 | * Returns the nth parameter in the request. The index zero-based. |
||
124 | * |
||
125 | * @param integer $i the index of the parameter to fetch (zero based) |
||
126 | * |
||
127 | * @return Value the i-th parameter |
||
128 | */ |
||
129 | 448 | public function getParam($i) |
|
133 | |||
134 | /** |
||
135 | * Returns the number of parameters in the message. |
||
136 | * |
||
137 | * @return integer the number of parameters currently set |
||
138 | */ |
||
139 | 467 | public function getNumParams() |
|
143 | |||
144 | /** |
||
145 | * Given an open file handle, read all data available and parse it as an xmlrpc response. |
||
146 | * |
||
147 | * NB: the file handle is not closed by this function. |
||
148 | * NNB: might have trouble in rare cases to work on network streams, as we check for a read of 0 bytes instead of |
||
149 | * feof($fp). But since checking for feof(null) returns false, we would risk an infinite loop in that case, |
||
150 | * because we cannot trust the caller to give us a valid pointer to an open file... |
||
151 | * |
||
152 | * @param resource $fp stream pointer |
||
153 | * @param bool $headersProcessed |
||
154 | * @param string $returnType |
||
155 | * |
||
156 | * @return Response |
||
157 | */ |
||
158 | public function parseResponseFile($fp, $headersProcessed = false, $returnType = 'xmlrpcvals') |
||
166 | |||
167 | /** |
||
168 | * Parse the xmlrpc response contained in the string $data and return a Response object. |
||
169 | * |
||
170 | * When $this->debug has been set to a value greater than 0, will echo debug messages to screen while decoding. |
||
171 | * |
||
172 | * @param string $data the xmlrpc response, possibly including http headers |
||
173 | * @param bool $headersProcessed when true prevents parsing HTTP headers for interpretation of content-encoding and |
||
174 | * consequent decoding |
||
175 | * @param string $returnType decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or |
||
176 | * 'phpvals' |
||
177 | * |
||
178 | * @return Response |
||
179 | */ |
||
180 | 600 | public function parseResponse($data = '', $headersProcessed = false, $returnType = 'xmlrpcvals') |
|
344 | |||
345 | /** |
||
346 | * Kept the old name even if Request class was renamed, for compatibility. |
||
347 | * |
||
348 | * @return string |
||
349 | */ |
||
350 | 117 | public function kindOf() |
|
354 | |||
355 | /** |
||
356 | * Enables/disables the echoing to screen of the xmlrpc responses received. |
||
357 | * |
||
358 | * @param integer $level values 0, 1, 2 are supported |
||
359 | */ |
||
360 | 601 | public function setDebug($level) |
|
364 | } |
||
365 |
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.