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 WebResponse 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 WebResponse, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class WebResponse extends Response |
||
38 | { |
||
39 | /** |
||
40 | * @var array An array of all HTTP 1.0 status codes and their message. |
||
41 | */ |
||
42 | protected $http10StatusCodes = array( |
||
43 | '200' => "HTTP/1.0 200 OK", |
||
44 | '201' => "HTTP/1.0 201 Created", |
||
45 | '202' => "HTTP/1.0 202 Accepted", |
||
46 | '204' => "HTTP/1.0 204 No Content", |
||
47 | '205' => "HTTP/1.0 205 Reset Content", |
||
48 | '206' => "HTTP/1.0 206 Partial Content", |
||
49 | '300' => "HTTP/1.0 300 Multiple Choices", |
||
50 | '301' => "HTTP/1.0 301 Moved Permanently", |
||
51 | '302' => "HTTP/1.0 302 Found", |
||
52 | '304' => "HTTP/1.0 304 Not Modified", |
||
53 | '400' => "HTTP/1.0 400 Bad Request", |
||
54 | '401' => "HTTP/1.0 401 Unauthorized", |
||
55 | '402' => "HTTP/1.0 402 Payment Required", |
||
56 | '403' => "HTTP/1.0 403 Forbidden", |
||
57 | '404' => "HTTP/1.0 404 Not Found", |
||
58 | '405' => "HTTP/1.0 405 Method Not Allowed", |
||
59 | '406' => "HTTP/1.0 406 Not Acceptable", |
||
60 | '407' => "HTTP/1.0 407 Proxy Authentication Required", |
||
61 | '408' => "HTTP/1.0 408 Request Timeout", |
||
62 | '409' => "HTTP/1.0 409 Conflict", |
||
63 | '410' => "HTTP/1.0 410 Gone", |
||
64 | '411' => "HTTP/1.0 411 Length Required", |
||
65 | '412' => "HTTP/1.0 412 Precondition Failed", |
||
66 | '413' => "HTTP/1.0 413 Request Entity Too Large", |
||
67 | '414' => "HTTP/1.0 414 Request-URI Too Long", |
||
68 | '415' => "HTTP/1.0 415 Unsupported Media Type", |
||
69 | '416' => "HTTP/1.0 416 Requested Range Not Satisfiable", |
||
70 | '417' => "HTTP/1.0 417 Expectation Failed", |
||
71 | '500' => "HTTP/1.0 500 Internal Server Error", |
||
72 | '501' => "HTTP/1.0 501 Not Implemented", |
||
73 | '502' => "HTTP/1.0 502 Bad Gateway", |
||
74 | '503' => "HTTP/1.0 503 Service Unavailable", |
||
75 | '504' => "HTTP/1.0 504 Gateway Timeout", |
||
76 | '505' => "HTTP/1.0 505 HTTP Version Not Supported", |
||
77 | ); |
||
78 | |||
79 | /** |
||
80 | * @var array An array of all HTTP 1.1 status codes and their message. |
||
81 | */ |
||
82 | protected $http11StatusCodes = array( |
||
83 | '100' => "HTTP/1.1 100 Continue", |
||
84 | '101' => "HTTP/1.1 101 Switching Protocols", |
||
85 | '200' => "HTTP/1.1 200 OK", |
||
86 | '201' => "HTTP/1.1 201 Created", |
||
87 | '202' => "HTTP/1.1 202 Accepted", |
||
88 | '203' => "HTTP/1.1 203 Non-Authoritative Information", |
||
89 | '204' => "HTTP/1.1 204 No Content", |
||
90 | '205' => "HTTP/1.1 205 Reset Content", |
||
91 | '206' => "HTTP/1.1 206 Partial Content", |
||
92 | '300' => "HTTP/1.1 300 Multiple Choices", |
||
93 | '301' => "HTTP/1.1 301 Moved Permanently", |
||
94 | '302' => "HTTP/1.1 302 Found", |
||
95 | '303' => "HTTP/1.1 303 See Other", |
||
96 | '304' => "HTTP/1.1 304 Not Modified", |
||
97 | '305' => "HTTP/1.1 305 Use Proxy", |
||
98 | '307' => "HTTP/1.1 307 Temporary Redirect", |
||
99 | '400' => "HTTP/1.1 400 Bad Request", |
||
100 | '401' => "HTTP/1.1 401 Unauthorized", |
||
101 | '402' => "HTTP/1.1 402 Payment Required", |
||
102 | '403' => "HTTP/1.1 403 Forbidden", |
||
103 | '404' => "HTTP/1.1 404 Not Found", |
||
104 | '405' => "HTTP/1.1 405 Method Not Allowed", |
||
105 | '406' => "HTTP/1.1 406 Not Acceptable", |
||
106 | '407' => "HTTP/1.1 407 Proxy Authentication Required", |
||
107 | '408' => "HTTP/1.1 408 Request Timeout", |
||
108 | '409' => "HTTP/1.1 409 Conflict", |
||
109 | '410' => "HTTP/1.1 410 Gone", |
||
110 | '411' => "HTTP/1.1 411 Length Required", |
||
111 | '412' => "HTTP/1.1 412 Precondition Failed", |
||
112 | '413' => "HTTP/1.1 413 Request Entity Too Large", |
||
113 | '414' => "HTTP/1.1 414 Request-URI Too Long", |
||
114 | '415' => "HTTP/1.1 415 Unsupported Media Type", |
||
115 | '416' => "HTTP/1.1 416 Requested Range Not Satisfiable", |
||
116 | '417' => "HTTP/1.1 417 Expectation Failed", |
||
117 | '500' => "HTTP/1.1 500 Internal Server Error", |
||
118 | '501' => "HTTP/1.1 501 Not Implemented", |
||
119 | '502' => "HTTP/1.1 502 Bad Gateway", |
||
120 | '503' => "HTTP/1.1 503 Service Unavailable", |
||
121 | '504' => "HTTP/1.1 504 Gateway Timeout", |
||
122 | '505' => "HTTP/1.1 505 HTTP Version Not Supported", |
||
123 | ); |
||
124 | |||
125 | /** |
||
126 | * @var array The array with the HTTP status codes to be used here. |
||
127 | */ |
||
128 | protected $httpStatusCodes = null; |
||
129 | |||
130 | /** |
||
131 | * @var string The HTTP status code to send for the response. |
||
132 | */ |
||
133 | protected $httpStatusCode = '200'; |
||
134 | |||
135 | /** |
||
136 | * @var array The HTTP headers scheduled to be sent with the response. |
||
137 | */ |
||
138 | protected $httpHeaders = array(); |
||
139 | |||
140 | /** |
||
141 | * @var array The Cookies scheduled to be sent with the response. |
||
142 | */ |
||
143 | protected $cookies = array(); |
||
144 | |||
145 | /** |
||
146 | * @var array An array of redirect information, or null if no redirect. |
||
147 | */ |
||
148 | protected $redirect = null; |
||
149 | |||
150 | /** |
||
151 | * Initialize this Response. |
||
152 | * |
||
153 | * @param Context $context A Context instance. |
||
154 | * @param array $parameters An array of initialization parameters. |
||
155 | * |
||
156 | * @author David Zülke <[email protected]> |
||
157 | * @since 0.11.0 |
||
158 | */ |
||
159 | public function initialize(Context $context, array $parameters = array()) |
||
194 | |||
195 | /** |
||
196 | * Send all response data to the client. |
||
197 | * |
||
198 | * @param OutputType $outputType An optional Output Type object with information |
||
199 | * the response can use to send additional data, |
||
200 | * such as HTTP headers |
||
201 | * |
||
202 | * @author David Zülke <[email protected]> |
||
203 | * @since 0.11.0 |
||
204 | */ |
||
205 | public function send(OutputType $outputType = null) |
||
229 | |||
230 | /** |
||
231 | * Send the content for this response |
||
232 | * |
||
233 | * @author David Zülke <[email protected]> |
||
234 | * @since 0.11.0 |
||
235 | */ |
||
236 | public function sendContent() |
||
247 | |||
248 | /** |
||
249 | * Clear all response data. |
||
250 | * |
||
251 | * @author David Zülke <[email protected]> |
||
252 | * @since 0.11.0 |
||
253 | */ |
||
254 | public function clear() |
||
262 | |||
263 | /** |
||
264 | * Check whether or not some content is set. |
||
265 | * |
||
266 | * @return bool If any content is set, false otherwise. |
||
267 | * |
||
268 | * @author David Zülke <[email protected]> |
||
269 | * @since 0.11.6 |
||
270 | */ |
||
271 | public function hasContent() |
||
275 | |||
276 | /** |
||
277 | * Set the content type for the response. |
||
278 | * |
||
279 | * @param string $type A content type. |
||
280 | * |
||
281 | * @author David Zülke <[email protected]> |
||
282 | * @since 0.9.0 |
||
283 | */ |
||
284 | public function setContentType($type) |
||
288 | |||
289 | /** |
||
290 | * Retrieve the content type set for the response. |
||
291 | * |
||
292 | * @return string A content type, or null if none is set. |
||
293 | * |
||
294 | * @author David Zülke <[email protected]> |
||
295 | * @since 0.9.0 |
||
296 | */ |
||
297 | public function getContentType() |
||
306 | |||
307 | /** |
||
308 | * Import response metadata (headers, cookies) from another response. |
||
309 | * |
||
310 | * @param Response $otherResponse The other response to import information from. |
||
311 | * |
||
312 | * @author David Zülke <[email protected]> |
||
313 | * @since 0.11.0 |
||
314 | */ |
||
315 | public function merge(Response $otherResponse) |
||
336 | |||
337 | /** |
||
338 | * Check if the given HTTP status code is valid. |
||
339 | * |
||
340 | * @param string $code A numeric HTTP status code. |
||
341 | * |
||
342 | * @return bool True, if the code is valid, or false otherwise. |
||
343 | * |
||
344 | * @author David Zülke <[email protected]> |
||
345 | * @since 0.11.3 |
||
346 | */ |
||
347 | public function validateHttpStatusCode($code) |
||
352 | |||
353 | /** |
||
354 | * Sets a HTTP status code for the response. |
||
355 | * |
||
356 | * @param string $code A numeric HTTP status code. |
||
357 | * |
||
358 | * @author David Zülke <[email protected]> |
||
359 | * @since 0.11.0 |
||
360 | */ |
||
361 | public function setHttpStatusCode($code) |
||
370 | |||
371 | /** |
||
372 | * Gets the HTTP status code set for the response. |
||
373 | * |
||
374 | * @return string A numeric HTTP status code between 100 and 505, or null |
||
375 | * if no status code has been set. |
||
376 | * |
||
377 | * @author David Zülke <[email protected]> |
||
378 | * @since 0.11.0 |
||
379 | */ |
||
380 | public function getHttpStatusCode() |
||
384 | |||
385 | /** |
||
386 | * Normalizes a HTTP header names |
||
387 | * |
||
388 | * @param string $name A HTTP header name |
||
389 | * |
||
390 | * @return string A normalized HTTP header name |
||
391 | * |
||
392 | * @author David Zülke <[email protected]> |
||
393 | * @since 0.11.0 |
||
394 | */ |
||
395 | public function normalizeHttpHeaderName($name) |
||
405 | |||
406 | /** |
||
407 | * Retrieve the HTTP header values set for the response. |
||
408 | * |
||
409 | * @param string $name A HTTP header field name. |
||
410 | * |
||
411 | * @return array All values set for that header, or null if no headers set |
||
412 | * |
||
413 | * @author David Zülke <[email protected]> |
||
414 | * @since 0.11.0 |
||
415 | */ |
||
416 | View Code Duplication | public function getHttpHeader($name) |
|
425 | |||
426 | /** |
||
427 | * Retrieve the HTTP headers set for the response. |
||
428 | * |
||
429 | * @return array An associative array of HTTP header names and values. |
||
430 | * |
||
431 | * @author David Zülke <[email protected]> |
||
432 | * @since 0.11.0 |
||
433 | */ |
||
434 | public function getHttpHeaders() |
||
438 | |||
439 | /** |
||
440 | * Check if an HTTP header has been set for the response. |
||
441 | * |
||
442 | * @param string $name A HTTP header field name. |
||
443 | * |
||
444 | * @return bool true if the header exists, false otherwise. |
||
445 | * |
||
446 | * @author David Zülke <[email protected]> |
||
447 | * @since 0.11.0 |
||
448 | */ |
||
449 | View Code Duplication | public function hasHttpHeader($name) |
|
458 | |||
459 | /** |
||
460 | * Set a HTTP header for the response |
||
461 | * |
||
462 | * @param string $name A HTTP header field name. |
||
463 | * @param mixed $value A HTTP header field value, of an array of values. |
||
464 | * @param bool $replace If true, a header with that name will be overwritten, |
||
465 | * otherwise, the value will be appended. |
||
466 | * |
||
467 | * @author David Zülke <[email protected]> |
||
468 | * @since 0.11.0 |
||
469 | */ |
||
470 | public function setHttpHeader($name, $value, $replace = true) |
||
482 | |||
483 | /** |
||
484 | * Send a cookie. |
||
485 | * |
||
486 | * @param string $name A cookie name. |
||
487 | * @param mixed $value Data to store into a cookie. If null or empty cookie |
||
488 | * will be tried to be removed. |
||
489 | * @param mixed $lifetime The lifetime of the cookie in seconds. When you pass 0 |
||
490 | * the cookie will be valid until the browser is closed. |
||
491 | * You can also use a strtotime() string instead of an int. |
||
492 | * @param string $path The path on the server the cookie will be available on. |
||
493 | * @param string $domain The domain the cookie is available on. |
||
494 | * @param bool $secure Indicates that the cookie should only be transmitted |
||
495 | * over a secure HTTPS connection. |
||
496 | * @param bool $httponly Whether the cookie will be made accessible only through |
||
497 | * the HTTP protocol, and not to client-side scripts. |
||
498 | * @param callable|bool $encodeCallback Callback to encode the cookie value. Set to false |
||
499 | * if you did already encode the value on your own. |
||
500 | * |
||
501 | * @throws AgaviException If $encodeCallback is neither false nor callable. |
||
502 | * |
||
503 | * @author Veikko Mäkinen <[email protected]> |
||
504 | * @author David Zülke <[email protected]> |
||
505 | * @since 0.11.0 |
||
506 | */ |
||
507 | public function setCookie($name, $value, $lifetime = null, $path = null, $domain = null, $secure = null, $httponly = null, $encodeCallback = null) |
||
530 | |||
531 | /** |
||
532 | * Unset an existing cookie. |
||
533 | * All arguments must reflect the values of the cookie that is already set. |
||
534 | * |
||
535 | * @param string $name A cookie name. |
||
536 | * @param string $path The path on the server the cookie will be available on. |
||
537 | * @param string $domain The domain the cookie is available on. |
||
538 | * @param bool $secure Indicates that the cookie should only be transmitted |
||
539 | * over a secure HTTPS connection. |
||
540 | * @param bool $httponly Whether the cookie will be made accessible only through |
||
541 | * the HTTP protocol, and not to client-side scripts. |
||
542 | * |
||
543 | * @author Ross Lawley <[email protected]> |
||
544 | * @author David Zülke <[email protected]> |
||
545 | * @since 0.11.0 |
||
546 | */ |
||
547 | public function unsetCookie($name, $path = null, $domain = null, $secure = null, $httponly = null) |
||
553 | |||
554 | /** |
||
555 | * Get a cookie set for later sending. |
||
556 | * |
||
557 | * @param string $name The name of the cookie. |
||
558 | * |
||
559 | * @return array An associative array containing the cookie data or null |
||
560 | * if no cookie with that name has been set. |
||
561 | * |
||
562 | * @author David Zülke <[email protected]> |
||
563 | * @since 0.11.0 |
||
564 | */ |
||
565 | public function getCookie($name) |
||
571 | |||
572 | /** |
||
573 | * Check if a cookie has been set for later sending. |
||
574 | * |
||
575 | * @param string $name The name of the cookie. |
||
576 | * |
||
577 | * @return bool True if a cookie with that name has been set, else false. |
||
578 | * |
||
579 | * @author David Zülke <[email protected]> |
||
580 | * @since 0.11.0 |
||
581 | */ |
||
582 | public function hasCookie($name) |
||
586 | |||
587 | /** |
||
588 | * Remove a cookie previously set for later sending. |
||
589 | * |
||
590 | * This method cannot be used to unset a cookie. It's purpose is to remove a |
||
591 | * cookie from the list of cookies to be sent along with the response. If you |
||
592 | * wish to remove an existing cookie, use the setCookie method and supply null |
||
593 | * as the value. |
||
594 | * |
||
595 | * @param string $name The name of the cookie. |
||
596 | * |
||
597 | * @author David Zülke <[email protected]> |
||
598 | * @since 0.11.0 |
||
599 | */ |
||
600 | public function removeCookie($name) |
||
606 | |||
607 | /** |
||
608 | * Get a list of cookies set for later sending. |
||
609 | * |
||
610 | * @return array An associative array of cookie names (key) and cookie |
||
611 | * information (value, associative array). |
||
612 | * |
||
613 | * @author David Zülke <[email protected]> |
||
614 | * @since 0.11.0 |
||
615 | */ |
||
616 | public function getCookies() |
||
620 | |||
621 | /** |
||
622 | * Remove the HTTP header set for the response |
||
623 | * |
||
624 | * @param string $name A HTTP header field name. |
||
625 | * |
||
626 | * @return mixed The removed header's value or null if header was not set. |
||
627 | * |
||
628 | * @author David Zülke <[email protected]> |
||
629 | * @since 0.11.0 |
||
630 | */ |
||
631 | View Code Duplication | public function removeHttpHeader($name) |
|
641 | |||
642 | /** |
||
643 | * Clears the HTTP headers set for this response. |
||
644 | * |
||
645 | * @author David Zülke <[email protected]> |
||
646 | * @since 0.11.0 |
||
647 | */ |
||
648 | public function clearHttpHeaders() |
||
652 | |||
653 | /** |
||
654 | * Sends HTTP Status code, headers and cookies |
||
655 | * |
||
656 | * @author David Zülke <[email protected]> |
||
657 | * @since 0.11.0 |
||
658 | */ |
||
659 | protected function sendHttpResponseHeaders(OutputType $outputType = null) |
||
741 | |||
742 | /** |
||
743 | * Redirect externally. |
||
744 | * |
||
745 | * @param mixed $location Where to redirect. |
||
746 | * @param int $code |
||
747 | * |
||
748 | * @author David Zülke <[email protected]> |
||
749 | * @since 0.11.0 |
||
750 | */ |
||
751 | public function setRedirect($location, $code = 302) |
||
758 | |||
759 | /** |
||
760 | * Get info about the set redirect. |
||
761 | * |
||
762 | * @return array An assoc array of redirect info, or null if none set. |
||
763 | * |
||
764 | * @author David Zülke <[email protected]> |
||
765 | * @since 0.11.0 |
||
766 | */ |
||
767 | public function getRedirect() |
||
771 | |||
772 | /** |
||
773 | * Check if a redirect is set. |
||
774 | * |
||
775 | * @return bool true, if a redirect is set, otherwise false |
||
776 | * |
||
777 | * @author David Zülke <[email protected]> |
||
778 | * @since 0.11.0 |
||
779 | */ |
||
780 | public function hasRedirect() |
||
784 | |||
785 | /** |
||
786 | * Clear any set redirect information. |
||
787 | * |
||
788 | * @author David Zülke <[email protected]> |
||
789 | * @since 0.11.0 |
||
790 | */ |
||
791 | public function clearRedirect() |
||
795 | } |
||
796 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.