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 |
||
37 | abstract class DriverAbstract extends ObjectAbstract implements DriverInterface, ErrorAwareInterface, ExtensionAwareInterface |
||
38 | { |
||
39 | use ErrorAwareTrait, ExtensionAwareTrait; |
||
40 | |||
41 | /** |
||
42 | * Store meta data in a seperate file |
||
43 | * |
||
44 | * @var bool |
||
45 | * @access protected |
||
46 | */ |
||
47 | protected $use_metafile = false; |
||
48 | |||
49 | /** |
||
50 | * {@inheritDoc} |
||
51 | */ |
||
52 | public function exists(/*# string */ $path)/*# : bool */ |
||
57 | |||
58 | /** |
||
59 | * {@inheritDoc} |
||
60 | */ |
||
61 | public function getContent(/*# string */ $path, /*# bool */ $stream = false) |
||
75 | |||
76 | /** |
||
77 | * {@inheritDoc} |
||
78 | */ |
||
79 | public function getMeta(/*# string */ $path)/*# : array */ |
||
94 | |||
95 | /** |
||
96 | * {@inheritDoc} |
||
97 | */ |
||
98 | public function setContent(/*# string */ $path, $content)/*# : bool */ |
||
116 | |||
117 | /** |
||
118 | * {@inheritDoc} |
||
119 | */ |
||
120 | public function setMeta(/*# string */ $path, array $meta)/*# : bool */ |
||
136 | |||
137 | /** |
||
138 | * {@inheritDoc} |
||
139 | */ |
||
140 | View Code Duplication | public function rename(/*# string */ $from, /*# string */ $to)/*# : bool */ |
|
1 ignored issue
–
show
|
|||
141 | { |
||
142 | $real_from = $this->realPath($from); |
||
143 | $real_to = $this->realPath($to); |
||
144 | |||
145 | if ($this->fixPath($real_from, $real_to)) { |
||
146 | if ($this->isDir($real_from)) { |
||
147 | $res = $this->renameDir($real_from, $real_to); |
||
148 | } else { |
||
149 | $res = $this->renameFile($real_from, $real_to); |
||
150 | } |
||
151 | |||
152 | return $res ?: $this->setError( |
||
153 | Message::get(Message::STR_RENAME_FAIL, $real_from, $real_to), |
||
154 | Message::STR_RENAME_FAIL |
||
155 | ); |
||
156 | } |
||
157 | return false; |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * {@inheritDoc} |
||
162 | */ |
||
163 | View Code Duplication | public function copy(/*# string */ $from, /*# string */ $to)/*# : bool */ |
|
1 ignored issue
–
show
|
|||
164 | { |
||
165 | $real_from = $this->realPath($from); |
||
166 | $real_to = $this->realPath($to); |
||
167 | |||
168 | if ($this->fixPath($real_from, $real_to)) { |
||
169 | if ($this->isDir($real_from)) { |
||
170 | $res = $this->copyDir($real_from, $real_to); |
||
171 | } else { |
||
172 | $res = $this->copyFile($real_from, $real_to); |
||
173 | } |
||
174 | |||
175 | return $res ?: $this->setError( |
||
176 | Message::get(Message::STR_COPY_FAIL, $real_from, $real_to), |
||
177 | Message::STR_COPY_FAIL |
||
178 | ); |
||
179 | } |
||
180 | return false; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * {@inheritDoc} |
||
185 | */ |
||
186 | public function delete(/*# string */ $path)/*# : bool */ |
||
199 | |||
200 | /** |
||
201 | * Returns driver specific real path |
||
202 | * @param string $path |
||
203 | * @return string |
||
204 | * @access protected |
||
205 | */ |
||
206 | abstract protected function realPath(/*# string */ $path)/*# : string */; |
||
207 | |||
208 | /** |
||
209 | * Exists of real path |
||
210 | * |
||
211 | * @param string $realPath |
||
212 | * @return bool |
||
213 | * @access protected |
||
214 | */ |
||
215 | abstract protected function realExists(/*# string */ $realPath)/*# : bool */; |
||
216 | |||
217 | /** |
||
218 | * Is path a directory |
||
219 | * |
||
220 | * @param string $realPath |
||
221 | * @return bool |
||
222 | * @access protected |
||
223 | */ |
||
224 | abstract protected function isDir(/*# string */ $realPath)/*# : bool */; |
||
225 | |||
226 | /** |
||
227 | * Read directory, returns an array of paths in this directory |
||
228 | * |
||
229 | * @param string $realPath |
||
230 | * @param string $prefix prefix to prepend to the results |
||
231 | * @return array |
||
232 | * @access protected |
||
233 | */ |
||
234 | abstract protected function readDir( |
||
238 | |||
239 | /** |
||
240 | * Open read stream |
||
241 | * |
||
242 | * @param string $realPath |
||
243 | * @return resource|null |
||
244 | * @access protected |
||
245 | */ |
||
246 | abstract protected function openReadStream(/*# string */ $realPath); |
||
247 | |||
248 | /** |
||
249 | * Read file and returns all the content |
||
250 | * |
||
251 | * @param string $realPath |
||
252 | * @return string|null |
||
253 | * @access protected |
||
254 | */ |
||
255 | abstract protected function readFile(/*# string */ $realPath); |
||
256 | |||
257 | /** |
||
258 | * Get the meta data |
||
259 | * |
||
260 | * @param string $realPath |
||
261 | * @return array |
||
262 | * @access protected |
||
263 | */ |
||
264 | abstract protected function getRealMeta(/*# string */ $realPath)/*# : array */; |
||
265 | |||
266 | /** |
||
267 | * Make sure path directory exits. |
||
268 | * |
||
269 | * @return bool |
||
270 | * @access protected |
||
271 | */ |
||
272 | abstract protected function fixPath()/*# : bool */; |
||
273 | |||
274 | /** |
||
275 | * Write to file from stream |
||
276 | * |
||
277 | * @param string $realPath |
||
278 | * @param resource $resource |
||
279 | * @return bool |
||
280 | * @access protected |
||
281 | */ |
||
282 | abstract protected function writeStream( |
||
286 | |||
287 | /** |
||
288 | * Write to file |
||
289 | * |
||
290 | * @param string $realPath |
||
291 | * @param string $content |
||
292 | * @return bool |
||
293 | * @access protected |
||
294 | */ |
||
295 | abstract protected function writeFile( |
||
299 | |||
300 | /** |
||
301 | * Write meta data |
||
302 | * |
||
303 | * @param string $realPath |
||
304 | * @param array $meta |
||
305 | * @return bool |
||
306 | * @access protected |
||
307 | */ |
||
308 | abstract protected function setRealMeta( |
||
312 | |||
313 | /** |
||
314 | * Rename directory |
||
315 | * |
||
316 | * @param string $from |
||
317 | * @param string $to |
||
318 | * @return bool |
||
319 | * @access protected |
||
320 | */ |
||
321 | abstract protected function renameDir( |
||
325 | |||
326 | /** |
||
327 | * Rename file |
||
328 | * |
||
329 | * @param string $from |
||
330 | * @param string $to |
||
331 | * @return bool |
||
332 | * @access protected |
||
333 | */ |
||
334 | abstract protected function renameFile( |
||
338 | |||
339 | /** |
||
340 | * Copy directory |
||
341 | * |
||
342 | * @param string $from |
||
343 | * @param string $to |
||
344 | * @return bool |
||
345 | * @access protected |
||
346 | */ |
||
347 | abstract protected function copyDir( |
||
351 | |||
352 | /** |
||
353 | * Copy file |
||
354 | * |
||
355 | * @param string $from |
||
356 | * @param string $to |
||
357 | * @return bool |
||
358 | * @access protected |
||
359 | */ |
||
360 | abstract protected function copyFile( |
||
364 | |||
365 | /** |
||
366 | * Delete directory |
||
367 | * |
||
368 | * @param string $realPath |
||
369 | * @return bool |
||
370 | * @access protected |
||
371 | */ |
||
372 | abstract protected function deleteDir(/*# string */ $realPath)/*# : bool */; |
||
373 | |||
374 | /** |
||
375 | * Delete the file |
||
376 | * |
||
377 | * @param string $realPath |
||
378 | * @return bool |
||
379 | * @access protected |
||
380 | */ |
||
381 | abstract protected function deleteFile(/*# string */ $realPath)/*# : bool */; |
||
382 | } |
||
383 |
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
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.