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 Cache 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 Cache, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class Cache implements \Countable, CacheInterface |
||
19 | { |
||
20 | const FIELD_NAME_VALUE = 'v'; |
||
21 | const FIELD_NAME_EXPIRED = 'e'; |
||
22 | const FIELD_NAME_TAGS = 't'; |
||
23 | |||
24 | private $collection; |
||
25 | |||
26 | /** |
||
27 | * Cache constructor. |
||
28 | * @param Database $database |
||
29 | * @param string $collectionName namespace of cache |
||
30 | */ |
||
31 | public function __construct(Database $database, $collectionName) |
||
46 | |||
47 | /** |
||
48 | * @return Cache |
||
49 | */ |
||
50 | public function init() |
||
55 | |||
56 | /** |
||
57 | * Persists a set of key => value pairs in the cache, with an optional TTL. |
||
58 | * |
||
59 | * @param array $values A list of key => value pairs for a multiple-set operation. |
||
60 | * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and |
||
61 | * the driver supports TTL then the library may set a default value |
||
62 | * for it or let the driver take care of that. |
||
63 | * @param array $tags List of tags |
||
64 | * |
||
65 | * @return bool True on success and false on failure. |
||
66 | * |
||
67 | * @throws \Psr\SimpleCache\InvalidArgumentException |
||
68 | * MUST be thrown if $values is neither an array nor a Traversable, |
||
69 | * or if any of the $values are not a legal value. |
||
70 | */ |
||
71 | public function setMultiple($values, $ttl = null, array $tags = array()) |
||
117 | |||
118 | /** |
||
119 | * Set with expiration on concrete date |
||
120 | * |
||
121 | * @deprecated Use self::set() with calculated ttl |
||
122 | * |
||
123 | * @param int|string $key |
||
124 | * @param mixed $value |
||
125 | * @param int $expirationTime |
||
126 | * @param array $tags |
||
127 | * |
||
128 | * @throws Exception |
||
129 | * |
||
130 | * @return bool |
||
131 | */ |
||
132 | public function setDueDate($key, $value, $expirationTime, array $tags = null) |
||
136 | |||
137 | /** |
||
138 | * Set key that never expired |
||
139 | * |
||
140 | * @deprecated Use self::set() with null in ttl |
||
141 | * |
||
142 | * @param int|string $key |
||
143 | * @param mixed $value |
||
144 | * @param array $tags |
||
145 | * |
||
146 | * @return bool |
||
147 | */ |
||
148 | public function setNeverExpired($key, $value, array $tags = null) |
||
152 | |||
153 | /** |
||
154 | * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. |
||
155 | * |
||
156 | * @param string $key The key of the item to store. |
||
157 | * @param mixed $value The value of the item to store, must be serializable. |
||
158 | * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and |
||
159 | * the driver supports TTL then the library may set a default value |
||
160 | * for it or let the driver take care of that. |
||
161 | * @param array $tags List of tags |
||
162 | * |
||
163 | * @return bool True on success and false on failure. |
||
164 | * |
||
165 | * @throws InvalidArgumentException |
||
166 | * @throws CacheException |
||
167 | */ |
||
168 | public function set($key, $value, $ttl = null, array $tags = null) |
||
210 | |||
211 | /** |
||
212 | * @param array $keys |
||
213 | * @param mixed|null $default |
||
214 | * |
||
215 | * @return array |
||
216 | */ |
||
217 | public function getMultiple($keys, $default = null) |
||
243 | |||
244 | /** |
||
245 | * Get value by key |
||
246 | * |
||
247 | * @param string $key |
||
248 | * @param mixed $default |
||
249 | * |
||
250 | * @return mixed |
||
251 | */ |
||
252 | public function get($key, $default = null) |
||
271 | |||
272 | |||
273 | /** |
||
274 | * Clear all cache |
||
275 | * |
||
276 | * @return bool |
||
277 | */ |
||
278 | public function clear() |
||
288 | |||
289 | /** |
||
290 | * Delete an item from the cache by its unique key. |
||
291 | * |
||
292 | * @param string $key The unique cache key of the item to delete. |
||
293 | * |
||
294 | * @return bool True if the item was successfully removed. False if there was an error. |
||
295 | * |
||
296 | * @throws \Psr\SimpleCache\InvalidArgumentException |
||
297 | * MUST be thrown if the $key string is not a legal value. |
||
298 | */ |
||
299 | public function delete($key) |
||
315 | |||
316 | /** |
||
317 | * Deletes multiple cache items in a single operation. |
||
318 | * |
||
319 | * @param array $keys A list of string-based keys to be deleted. |
||
320 | * |
||
321 | * @return bool True if the items were successfully removed. False if there was an error. |
||
322 | * |
||
323 | * @throws \Psr\SimpleCache\InvalidArgumentException |
||
324 | * MUST be thrown if $keys is neither an array nor a Traversable, |
||
325 | * or if any of the $keys are not a legal value. |
||
326 | */ |
||
327 | public function deleteMultiple($keys) |
||
341 | |||
342 | /** |
||
343 | * Delete documents by tag |
||
344 | */ |
||
345 | public function deleteMatchingTag($tag) |
||
353 | |||
354 | /** |
||
355 | * Delete documents by tag |
||
356 | */ |
||
357 | public function deleteNotMatchingTag($tag) |
||
365 | |||
366 | /** |
||
367 | * Delete documents by tag |
||
368 | * Document deletes if it contains all passed tags |
||
369 | */ |
||
370 | public function deleteMatchingAllTags(array $tags) |
||
378 | |||
379 | /** |
||
380 | * Delete documents by tag |
||
381 | * Document deletes if it not contains all passed tags |
||
382 | */ |
||
383 | public function deleteMatchingNoneOfTags(array $tags) |
||
391 | |||
392 | /** |
||
393 | * Delete documents by tag |
||
394 | * Document deletes if it contains any of passed tags |
||
395 | */ |
||
396 | public function deleteMatchingAnyTag(array $tags) |
||
404 | |||
405 | /** |
||
406 | * Delete documents by tag |
||
407 | * Document deletes if it contains any of passed tags |
||
408 | */ |
||
409 | public function deleteNotMatchingAnyTag(array $tags) |
||
417 | |||
418 | /** |
||
419 | * Get total count of documents in cache |
||
420 | * |
||
421 | * @return int |
||
422 | */ |
||
423 | public function count() |
||
427 | |||
428 | /** |
||
429 | * Check if cache has key |
||
430 | * |
||
431 | * @param string $key |
||
432 | * @return bool |
||
433 | */ |
||
434 | public function has($key) |
||
438 | } |
||
439 |
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.