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 Consumer 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 Consumer, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Consumer implements ConsumerInterface, SignalHandlingConsumerInterface |
||
17 | { |
||
18 | /** @var \Aws\Sqs\SqsClient */ |
||
19 | protected $client; |
||
20 | protected $queueUrl; |
||
21 | protected $queueName; |
||
22 | protected $callback; |
||
23 | |||
24 | protected $routingKey; |
||
25 | protected $routingKeyRegexp; |
||
26 | protected $logger; |
||
27 | // The message attribute used to store content-type. To be kept in sync with the Producer |
||
28 | protected $contentTypeAttribute = 'contentType'; |
||
29 | protected $routingAttribute = 'routingKey'; |
||
30 | protected $debug = false; |
||
31 | protected $forceStop = false; |
||
32 | protected $forceStopReason; |
||
33 | protected $dispatchSignals = false; |
||
34 | protected $memoryLimit = null; |
||
35 | // NB: when changing the defaults below, alter as well KaliopQueueingPluginsSQSExtension::load |
||
36 | /** @var int $requestBatchSize how many messages to receive in each poll by default */ |
||
37 | protected $requestBatchSize = 1; |
||
38 | /** @var int $requestTimeout how long to wait for messages in each request. Switches between long and short polling */ |
||
39 | protected $requestTimeout = 0; |
||
40 | /** @var int the minimum interval between two queue polls - in microseconds */ |
||
41 | protected $pollingIntervalUs = 200000; |
||
42 | /** @var int $gcProbability the probability of calling gc_collect_cycles at the end of every poll */ |
||
43 | protected $gcProbability = 1; |
||
44 | |||
45 | const MAX_MESSAGES_PER_REQUEST = 10; |
||
46 | const MAX_REQUEST_TIMEOUT = 20; |
||
47 | |||
48 | 9 | public function __construct(array $config) |
|
52 | |||
53 | public function setLogger(LoggerInterface $logger = null) |
||
59 | |||
60 | /** |
||
61 | * Enabled debug. At the moment can not disable it |
||
62 | * @param bool|array $debug |
||
63 | * @return $this |
||
64 | * |
||
65 | * @todo test if using $handlerList->removeByInstance we can disable debug as well |
||
66 | */ |
||
67 | 4 | View Code Duplication | public function setDebug($debug) { |
78 | |||
79 | /** |
||
80 | * @param int $limit MB |
||
81 | * @return Consumer |
||
82 | */ |
||
83 | public function setMemoryLimit($limit) |
||
89 | |||
90 | /** |
||
91 | * @param string $key |
||
92 | * @return Consumer |
||
93 | */ |
||
94 | 9 | public function setRoutingKey($key) |
|
100 | |||
101 | /** |
||
102 | * @param MessageConsumerInterface $callback |
||
103 | * @return Consumer |
||
104 | */ |
||
105 | 4 | public function setCallback($callback) |
|
114 | |||
115 | 9 | public function setQueueName($queueName) |
|
121 | |||
122 | /** |
||
123 | * The number of messages to download in every request to the SQS API. |
||
124 | * Bigger numbers are better for performances, but there is a limit on the size of the response which SQS will send. |
||
125 | * @param int $amount |
||
126 | * @return Consumer |
||
127 | */ |
||
128 | public function setRequestBatchSize($amount) |
||
134 | |||
135 | public function setRequestTimeout($timeout) |
||
141 | |||
142 | public function setPollingInterval($intervalUs) |
||
148 | |||
149 | public function setGCProbability($probability) |
||
155 | |||
156 | /** |
||
157 | * @see http://docs.aws.amazon.com/aws-sdk-php/v3/api/api-sqs-2012-11-05.html#receivemessage |
||
158 | * |
||
159 | * @param int $amount 0 for unlimited |
||
160 | * @param int $timeout seconds 0 for unlimited. NB: any value > 0 activates 'long polling' mode |
||
161 | * @return void |
||
162 | */ |
||
163 | 4 | public function consume($amount, $timeout = 0) |
|
279 | |||
280 | /** |
||
281 | * Adopt the RabbitMQ routing key algorithm: |
||
282 | * - split on dots |
||
283 | * - * matches one word (q: also empty ones?) |
||
284 | * - # matches any words |
||
285 | * |
||
286 | * @todo the current implementation is naive and does probably not match RabbitMq if the routing key is something like aaa.*b.ccc |
||
287 | * A better implementation would probably involve usage of a trie |
||
288 | * Some pointers on how to implement it fast: http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-June/013564.html |
||
289 | * @see setRoutingKey |
||
290 | * |
||
291 | * @param array $message |
||
292 | * @return bool |
||
293 | */ |
||
294 | 4 | protected function matchRoutingKey(array $message) |
|
311 | |||
312 | /** |
||
313 | * @param string $queueUrl the complete queue name as used by SQS |
||
314 | * @return Consumer |
||
315 | */ |
||
316 | 9 | public function setQueueUrl($queueUrl) |
|
322 | |||
323 | /** |
||
324 | * @return string the complete queue name as used by SQS |
||
325 | */ |
||
326 | public function getQueueUrl() |
||
330 | |||
331 | public function setHandleSignals($doHandle) |
||
335 | |||
336 | |||
337 | public function forceStop($reason = '') |
||
342 | |||
343 | /** |
||
344 | * Dispatches signals and throws an exception if user wants to stop. To be called at execution points when there is no data loss |
||
345 | * |
||
346 | * @throws ForcedStopException |
||
347 | */ |
||
348 | 4 | protected function maybeStopConsumer() |
|
366 | } |
||
367 |
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.