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 WebRequestDataHolder 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 WebRequestDataHolder, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 34 | class WebRequestDataHolder extends RequestDataHolder implements CookiesRequestDataHolderInterface, FilesRequestDataHolderInterface, HeadersRequestDataHolderInterface |
||
| 35 | { |
||
| 36 | /** |
||
| 37 | * @constant Constant for source name of cookies. |
||
| 38 | */ |
||
| 39 | const SOURCE_COOKIES = 'cookies'; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * @constant Constant for source name of files. |
||
| 43 | */ |
||
| 44 | const SOURCE_FILES = 'files'; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * @constant Constant for source name of HTTP headers. |
||
| 48 | */ |
||
| 49 | const SOURCE_HEADERS = 'headers'; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * @var array An (proper) array of files uploaded during the request. |
||
| 53 | */ |
||
| 54 | protected $files = array(); |
||
| 55 | |||
| 56 | /** |
||
| 57 | * @var array An array of cookies set in the request. |
||
| 58 | */ |
||
| 59 | protected $cookies = array(); |
||
| 60 | |||
| 61 | /** |
||
| 62 | * @var array An array of headers sent with the request. |
||
| 63 | */ |
||
| 64 | protected $headers = array(); |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Checks if there is a value of a parameter is empty or not set. |
||
| 68 | * |
||
| 69 | * @param string $field The field name. |
||
| 70 | * |
||
| 71 | * @return bool The result. |
||
| 72 | * |
||
| 73 | * @author David Zülke <[email protected]> |
||
| 74 | * @author Dominik del Bondio <[email protected]> |
||
| 75 | * @since 0.11.0 |
||
| 76 | */ |
||
| 77 | public function isParameterValueEmpty($field) |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Clear all cookies. |
||
| 85 | * |
||
| 86 | * @author Dominik del Bondio <[email protected]> |
||
| 87 | * @since 0.11.0 |
||
| 88 | */ |
||
| 89 | public function clearCookies() |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Indicates whether or not a Cookie exists. |
||
| 96 | * |
||
| 97 | * @param string $name A cookie name. |
||
| 98 | * |
||
| 99 | * @return bool True, if a cookie with that name exists, otherwise false. |
||
| 100 | * |
||
| 101 | * @author David Zülke <[email protected]> |
||
| 102 | * @since 0.11.0 |
||
| 103 | */ |
||
| 104 | View Code Duplication | public function hasCookie($name) |
|
| 115 | |||
| 116 | /** |
||
| 117 | * Checks if there is a value of a cookie is empty or not set. |
||
| 118 | * |
||
| 119 | * @param string $name The cookie name. |
||
| 120 | * |
||
| 121 | * @return bool The result. |
||
| 122 | * |
||
| 123 | * @author David Zülke <[email protected]> |
||
| 124 | * @author Dominik del Bondio <[email protected]> |
||
| 125 | * @since 0.11.0 |
||
| 126 | */ |
||
| 127 | public function isCookieValueEmpty($name) |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Retrieve a value stored into a cookie. |
||
| 134 | * |
||
| 135 | * @param string $name A cookie name. |
||
| 136 | * @param mixed $default A default value. |
||
| 137 | * |
||
| 138 | * @return mixed The value from the cookie, if such a cookie exists, |
||
| 139 | * otherwise null. |
||
| 140 | * |
||
| 141 | * @author Veikko Mäkinen <[email protected]> |
||
| 142 | * @author David Zülke <[email protected]> |
||
| 143 | * @since 0.11.0 |
||
| 144 | */ |
||
| 145 | View Code Duplication | public function &getCookie($name, $default = null) |
|
| 156 | |||
| 157 | /** |
||
| 158 | * Set a cookie. |
||
| 159 | * |
||
| 160 | * If a cookie with the name already exists the value will be overridden. |
||
| 161 | * |
||
| 162 | * @param string $name A cookie name. |
||
| 163 | * @param mixed $value A cookie value. |
||
| 164 | * |
||
| 165 | * @author Dominik del Bondio <[email protected]> |
||
| 166 | * @since 0.11.0 |
||
| 167 | */ |
||
| 168 | public function setCookie($name, $value) |
||
| 172 | |||
| 173 | /** |
||
| 174 | * Set an array of cookies. |
||
| 175 | * |
||
| 176 | * If an existing cookie name matches any of the keys in the supplied |
||
| 177 | * array, the associated value will be overridden. |
||
| 178 | * |
||
| 179 | * @param array $cookies An associative array of cookies and their values. |
||
| 180 | * |
||
| 181 | * @author Dominik del Bondio <[email protected]> |
||
| 182 | * @since 0.11.0 |
||
| 183 | */ |
||
| 184 | public function setCookies(array $cookies) |
||
| 188 | |||
| 189 | /** |
||
| 190 | * Remove a cookie. |
||
| 191 | * |
||
| 192 | * @param string $name The cookie name |
||
| 193 | * |
||
| 194 | * @return string The value of the removed cookie, if it had been set. |
||
| 195 | * |
||
| 196 | * @author David Zülke <[email protected]> |
||
| 197 | * @author Dominik del Bondio <[email protected]> |
||
| 198 | * @since 0.11.0 |
||
| 199 | */ |
||
| 200 | View Code Duplication | public function &removeCookie($name) |
|
| 213 | |||
| 214 | /** |
||
| 215 | * Retrieve all cookies. |
||
| 216 | * |
||
| 217 | * @return array The cookies. |
||
| 218 | * |
||
| 219 | * @author Dominik del Bondio <[email protected]> |
||
| 220 | * @since 0.11.0 |
||
| 221 | */ |
||
| 222 | public function &getCookies() |
||
| 226 | |||
| 227 | /** |
||
| 228 | * Retrieve an array of cookie names. |
||
| 229 | * |
||
| 230 | * @return array An indexed array of cookie names. |
||
| 231 | * |
||
| 232 | * @author David Zülke <[email protected]> |
||
| 233 | * @since 0.11.0 |
||
| 234 | */ |
||
| 235 | public function getCookieNames() |
||
| 239 | |||
| 240 | /** |
||
| 241 | * Retrieve an array of flattened cookie names. This means when a cookie is an |
||
| 242 | * array you wont get the name of the cookie in the result but instead all |
||
| 243 | * child keys appended to the name (like foo[0],foo[1][0], ...). |
||
| 244 | * |
||
| 245 | * @return array An indexed array of cookie names. |
||
| 246 | * |
||
| 247 | * @author David Zülke <[email protected]> |
||
| 248 | * @since 0.11.0 |
||
| 249 | */ |
||
| 250 | public function getFlatCookieNames() |
||
| 254 | |||
| 255 | /** |
||
| 256 | * Clear all headers. |
||
| 257 | * |
||
| 258 | * @author Dominik del Bondio <[email protected]> |
||
| 259 | * @since 0.11.0 |
||
| 260 | */ |
||
| 261 | public function clearHeaders() |
||
| 265 | |||
| 266 | /** |
||
| 267 | * Retrieve all HTTP headers. |
||
| 268 | * |
||
| 269 | * @return array A list of HTTP headers (keys in original PHP format). |
||
| 270 | * |
||
| 271 | * @author David Zülke <[email protected]> |
||
| 272 | * @since 0.11.0 |
||
| 273 | */ |
||
| 274 | public function &getHeaders() |
||
| 278 | |||
| 279 | /** |
||
| 280 | * Get a HTTP header. |
||
| 281 | * |
||
| 282 | * @param string $name Case-insensitive name of a header, using either a hyphen |
||
| 283 | * or an underscore as a separator. |
||
| 284 | * @param mixed $default A default value. |
||
| 285 | * |
||
| 286 | * @return string The header value, or null if header wasn't set. |
||
| 287 | * |
||
| 288 | * @author David Zülke <[email protected]> |
||
| 289 | * @since 0.11.0 |
||
| 290 | */ |
||
| 291 | public function &getHeader($name, $default = null) |
||
| 300 | |||
| 301 | /** |
||
| 302 | * Check if a HTTP header exists. |
||
| 303 | * |
||
| 304 | * @param string $name Case-insensitive name of a header, using either a hyphen |
||
| 305 | * or an underscore as a separator. |
||
| 306 | * |
||
| 307 | * @return bool True if the header was sent with the current request. |
||
| 308 | * |
||
| 309 | * @author David Zülke <[email protected]> |
||
| 310 | * @since 0.11.0 |
||
| 311 | */ |
||
| 312 | public function hasHeader($name) |
||
| 317 | |||
| 318 | /** |
||
| 319 | * Checks if there is a value of a header is empty or not set. |
||
| 320 | * |
||
| 321 | * @param string $name The header name. |
||
| 322 | * |
||
| 323 | * @return bool The result. |
||
| 324 | * |
||
| 325 | * @author David Zülke <[email protected]> |
||
| 326 | * @author Dominik del Bondio <[email protected]> |
||
| 327 | * @since 0.11.0 |
||
| 328 | */ |
||
| 329 | public function isHeaderValueEmpty($name) |
||
| 333 | /** |
||
| 334 | * Set a header. |
||
| 335 | * |
||
| 336 | * The header name is normalized before storing it. |
||
| 337 | * |
||
| 338 | * @param string $name A header name. |
||
| 339 | * @param mixed $value A header value. |
||
| 340 | * |
||
| 341 | * @author David Zülke <[email protected]> |
||
| 342 | * @author Dominik del Bondio <[email protected]> |
||
| 343 | * @since 0.11.0 |
||
| 344 | */ |
||
| 345 | public function setHeader($name, $value) |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Set an array of headers. |
||
| 352 | * |
||
| 353 | * @param array $headers An associative array of headers and their values. |
||
| 354 | * |
||
| 355 | * @author Dominik del Bondio <[email protected]> |
||
| 356 | * @since 0.11.0 |
||
| 357 | */ |
||
| 358 | public function setHeaders(array $headers) |
||
| 362 | |||
| 363 | /** |
||
| 364 | * Remove a HTTP header. |
||
| 365 | * |
||
| 366 | * @param string $name Case-insensitive name of a header, using either a hyphen |
||
| 367 | * or an underscore as a separator. |
||
| 368 | * |
||
| 369 | * @return string The value of the removed header, if it had been set. |
||
| 370 | * |
||
| 371 | * @author David Zülke <[email protected]> |
||
| 372 | * @since 0.11.0 |
||
| 373 | */ |
||
| 374 | public function &removeHeader($name) |
||
| 384 | |||
| 385 | /** |
||
| 386 | * Retrieve an array of header names. |
||
| 387 | * |
||
| 388 | * @return array An indexed array of header names in original PHP format. |
||
| 389 | * |
||
| 390 | * @author David Zülke <[email protected]> |
||
| 391 | * @since 0.11.0 |
||
| 392 | */ |
||
| 393 | public function getHeaderNames() |
||
| 397 | |||
| 398 | /** |
||
| 399 | * Retrieve an array of file information. |
||
| 400 | * |
||
| 401 | * @param string $name A file name. |
||
| 402 | * @param mixed $default A default return value. |
||
| 403 | * |
||
| 404 | * @return mixed An AgaviUploadedFile object with file information, or an |
||
| 405 | * array if the field name has child elements, or null (or |
||
| 406 | * the supplied default return value) no such file exists. |
||
| 407 | * |
||
| 408 | * @author David Zülke <[email protected]> |
||
| 409 | * @since 0.11.0 |
||
| 410 | */ |
||
| 411 | View Code Duplication | public function &getFile($name, $default = null) |
|
| 427 | |||
| 428 | /** |
||
| 429 | * Retrieve an array of files. |
||
| 430 | * |
||
| 431 | * @return array An associative array of files. |
||
| 432 | * |
||
| 433 | * @author David Zülke <[email protected]> |
||
| 434 | * @since 0.11.0 |
||
| 435 | */ |
||
| 436 | public function &getFiles() |
||
| 440 | |||
| 441 | /** |
||
| 442 | * Indicates whether or not a file exists. |
||
| 443 | * |
||
| 444 | * @param string $name A file name. |
||
| 445 | * |
||
| 446 | * @return bool true, if the file exists, otherwise false. |
||
| 447 | * |
||
| 448 | * @author David Zülke <[email protected]> |
||
| 449 | * @since 0.11.0 |
||
| 450 | */ |
||
| 451 | View Code Duplication | public function hasFile($name) |
|
| 464 | |||
| 465 | /** |
||
| 466 | * Indicates whether or not any files exist. |
||
| 467 | * |
||
| 468 | * @return bool true, if any files exist, otherwise false. |
||
| 469 | * |
||
| 470 | * @author David Zülke <[email protected]> |
||
| 471 | * @author Sean Kerr <[email protected]> |
||
| 472 | * @since 0.11.0 |
||
| 473 | */ |
||
| 474 | public function hasFiles() |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Checks if a file is empty, i.e. not set or set, but not actually uploaded. |
||
| 481 | * |
||
| 482 | * @param string $name The file name. |
||
| 483 | * |
||
| 484 | * @return bool The result. |
||
| 485 | * |
||
| 486 | * @author David Zülke <[email protected]> |
||
| 487 | * @author Dominik del Bondio <[email protected]> |
||
| 488 | * @since 0.11.0 |
||
| 489 | */ |
||
| 490 | View Code Duplication | public function isFileValueEmpty($name) |
|
| 498 | |||
| 499 | /** |
||
| 500 | * Removes file information for given file. |
||
| 501 | * |
||
| 502 | * @param string $name A file name |
||
| 503 | * |
||
| 504 | * @return mixed The old UploadedFile instance or array of elements. |
||
| 505 | * |
||
| 506 | * @author David Zülke <[email protected]> |
||
| 507 | * @author Dominik del Bondio <[email protected]> |
||
| 508 | * @since 0.11.0 |
||
| 509 | */ |
||
| 510 | View Code Duplication | public function &removeFile($name) |
|
| 523 | |||
| 524 | /** |
||
| 525 | * Set a file. |
||
| 526 | * |
||
| 527 | * If a file with the name already exists the value will be overridden. |
||
| 528 | * |
||
| 529 | * @param string $name A file name. |
||
| 530 | * @param UploadedFile $file An UploadedFile object. |
||
| 531 | * |
||
| 532 | * @author David Zülke <[email protected]> |
||
| 533 | * @since 0.11.0 |
||
| 534 | */ |
||
| 535 | public function setFile($name, UploadedFile $file) |
||
| 539 | |||
| 540 | /** |
||
| 541 | * Set an array of files. |
||
| 542 | * |
||
| 543 | * @param array $files An assoc array of names and AgaviUploadedFile objects. |
||
| 544 | * |
||
| 545 | * @author Dominik del Bondio <[email protected]> |
||
| 546 | * @since 0.11.0 |
||
| 547 | */ |
||
| 548 | public function setFiles(array $files) |
||
| 552 | |||
| 553 | /** |
||
| 554 | * Clear all files. |
||
| 555 | * |
||
| 556 | * @author Dominik del Bondio <[email protected]> |
||
| 557 | * @since 0.11.0 |
||
| 558 | */ |
||
| 559 | public function clearFiles() |
||
| 563 | |||
| 564 | /** |
||
| 565 | * Retrieve an array of file names. |
||
| 566 | * |
||
| 567 | * @return array An indexed array of file names. |
||
| 568 | * |
||
| 569 | * @author David Zülke <[email protected]> |
||
| 570 | * @since 0.11.0 |
||
| 571 | */ |
||
| 572 | public function getFileNames() |
||
| 576 | |||
| 577 | /** |
||
| 578 | * Retrieve an array of flattened file names. This means when a file is an |
||
| 579 | * array you wont get the name of the file in the result but instead all child |
||
| 580 | * keys appended to the name (like foo[0],foo[1][0], ...). |
||
| 581 | * |
||
| 582 | * @return array An indexed array of file names. |
||
| 583 | * |
||
| 584 | * @author David Zülke <[email protected]> |
||
| 585 | * @since 0.11.0 |
||
| 586 | */ |
||
| 587 | public function getFlatFileNames() |
||
| 591 | |||
| 592 | /** |
||
| 593 | * Constructor |
||
| 594 | * |
||
| 595 | * @param array $data An associative array of request data source names and |
||
| 596 | * data arrays. |
||
| 597 | * |
||
| 598 | * @author David Zülke <[email protected]> |
||
| 599 | * @since 0.11.0 |
||
| 600 | */ |
||
| 601 | public function __construct(array $data = array()) |
||
| 610 | |||
| 611 | /** |
||
| 612 | * Merge in Cookies from another request data holder. |
||
| 613 | * |
||
| 614 | * @param RequestDataHolder $other The other request data holder. |
||
| 615 | * |
||
| 616 | * @author David Zülke <[email protected]> |
||
| 617 | * @since 0.11.0 |
||
| 618 | */ |
||
| 619 | public function mergeCookies(RequestDataHolder $other) |
||
| 625 | |||
| 626 | /** |
||
| 627 | * Merge in Files from another request data holder. |
||
| 628 | * |
||
| 629 | * @param RequestDataHolder $other The other request data holder. |
||
| 630 | * |
||
| 631 | * @author David Zülke <[email protected]> |
||
| 632 | * @since 0.11.0 |
||
| 633 | */ |
||
| 634 | public function mergeFiles(RequestDataHolder $other) |
||
| 640 | |||
| 641 | /** |
||
| 642 | * Merge in Headers from another request data holder. |
||
| 643 | * |
||
| 644 | * @param RequestDataHolder $other The other request data holder. |
||
| 645 | * |
||
| 646 | * @author David Zülke <[email protected]> |
||
| 647 | * @since 0.11.0 |
||
| 648 | */ |
||
| 649 | public function mergeHeaders(RequestDataHolder $other) |
||
| 655 | } |
||
| 656 |
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.