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:
| 1 | <?php |
||
| 12 | class ContentVersionMatcher extends RepositoryMatcher implements MatcherInterface |
||
| 13 | { |
||
| 14 | const MATCH_STATUS_DRAFT = 'draft'; |
||
| 15 | const MATCH_STATUS_PUBLISHED = 'published'; |
||
| 16 | const MATCH_STATUS_ARCHIVED = 'archived'; |
||
| 17 | |||
| 18 | const MATCH_STATUS = 'version_status'; |
||
| 19 | const MATCH_VERSION = 'version'; |
||
| 20 | |||
| 21 | const STATUS_MAP = array( |
||
| 22 | self::MATCH_STATUS_DRAFT => VersionInfo::STATUS_DRAFT, |
||
| 23 | self::MATCH_STATUS_PUBLISHED => VersionInfo::STATUS_PUBLISHED, |
||
| 24 | self::MATCH_STATUS_ARCHIVED => VersionInfo::STATUS_ARCHIVED |
||
| 25 | ); |
||
| 26 | |||
| 27 | protected $allowedConditions = array( |
||
| 28 | self::MATCH_ALL, self::MATCH_AND, self::MATCH_OR, self::MATCH_NOT, |
||
| 29 | self::MATCH_STATUS, self::MATCH_VERSION, |
||
| 30 | // aliases |
||
| 31 | 'status' |
||
| 32 | ); |
||
| 33 | protected $returns = 'VersionInfo'; |
||
| 34 | |||
| 35 | protected $contentMatcher; |
||
| 36 | |||
| 37 | 80 | public function __construct(Repository $repository, MatcherInterface $contentMatcher) |
|
| 42 | |||
| 43 | public function match(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0, $limit = 0) |
||
| 54 | |||
| 55 | /** |
||
| 56 | * Like match, but will throw an exception if there are 0 or more than 1 items matching |
||
| 57 | * |
||
| 58 | * @param array $contentConditions |
||
| 59 | * @param array $versionConditions |
||
| 60 | * @param array $sort |
||
| 61 | * @param int $offset |
||
| 62 | * @return mixed |
||
| 63 | * @throws \Exception |
||
| 64 | */ |
||
| 65 | View Code Duplication | public function matchOne(array $contentConditions, array $versionConditions = array(), $sort = array(), $offset = 0) |
|
| 66 | { |
||
| 67 | $results = $this->match($contentConditions, $versionConditions, $sort, $offset, 2); |
||
| 68 | $count = count($results); |
||
| 69 | if ($count !== 1) { |
||
| 70 | throw new \Exception("Found $count " . $this->returns . " when expected exactly only one to match the conditions"); |
||
| 71 | } |
||
| 72 | return reset($results); |
||
| 73 | } |
||
| 74 | |||
| 75 | /** |
||
| 76 | * @param array $versionConditions |
||
| 77 | * @param Content $content |
||
| 78 | * @return VersionInfo[] key: obj_id/version_no |
||
| 79 | */ |
||
| 80 | public function matchContentVersions(array $versionConditions, Content $content) |
||
| 81 | { |
||
| 82 | $this->validateConditions($versionConditions); |
||
| 83 | |||
| 84 | foreach ($versionConditions as $key => $values) { |
||
| 85 | |||
| 86 | if (!is_array($values)) { |
||
| 87 | $values = array($values); |
||
| 88 | } |
||
| 89 | |||
| 90 | switch ($key) { |
||
| 91 | case 'status': |
||
| 92 | case self::MATCH_STATUS: |
||
| 93 | return $this->findContentVersionsByStatus($content, $values); |
||
| 94 | |||
| 95 | case self::MATCH_VERSION: |
||
| 96 | return $this->findContentVersionsByVersionNo($content, $values); |
||
| 97 | |||
| 98 | case self::MATCH_ALL: |
||
| 99 | return $this->findAllContentVersions($content); |
||
| 100 | |||
| 101 | case self::MATCH_AND: |
||
| 102 | return $this->matchAnd($values, $content); |
||
| 103 | |||
| 104 | case self::MATCH_OR: |
||
| 105 | return $this->matchOr($values, $content); |
||
| 106 | |||
| 107 | case self::MATCH_NOT: |
||
| 108 | return array_diff_key($this->findAllContentVersions($content), $this->matchContentVersions($values, $content)); |
||
| 109 | } |
||
| 110 | } |
||
| 111 | } |
||
| 112 | |||
| 113 | View Code Duplication | protected function matchAnd($conditionsArray, $content = null) |
|
| 135 | |||
| 136 | View Code Duplication | protected function matchOr($conditionsArray, $content = null) |
|
| 137 | { |
||
| 155 | |||
| 156 | /** |
||
| 157 | * @param Content $content |
||
| 158 | * @param string[] $values |
||
| 159 | * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no. |
||
| 160 | */ |
||
| 161 | protected function findContentVersionsByStatus(Content $content, array $values) |
||
| 174 | |||
| 175 | /** |
||
| 176 | * @param Content $content |
||
| 177 | * @param int[] $values |
||
| 178 | * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no. |
||
| 179 | */ |
||
| 180 | protected function findContentVersionsByVersionNo(Content $content, array $values) |
||
| 206 | |||
| 207 | /** |
||
| 208 | * @param Content $content |
||
| 209 | * @return VersionInfo[] key: obj_id/version_no, sorted in increasing version no. |
||
| 210 | */ |
||
| 211 | protected function findAllContentVersions(Content $content) |
||
| 223 | } |
||
| 224 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.