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 Queue 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 Queue, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | class Queue |
||
14 | { |
||
15 | /** |
||
16 | * @var PheanstalkInterface |
||
17 | */ |
||
18 | private $pheanstalk; |
||
19 | /** |
||
20 | * @var LoggerInterface |
||
21 | */ |
||
22 | private $logger; |
||
23 | /** |
||
24 | * @var int |
||
25 | */ |
||
26 | private $defaultTtr = PheanstalkInterface::DEFAULT_TTR; |
||
27 | /** |
||
28 | * @var ExecutorPool |
||
29 | */ |
||
30 | private $executorPool; |
||
31 | |||
32 | /** |
||
33 | * @param PheanstalkInterface $pheanstalk |
||
34 | * @param ExecutorPool $executorPool |
||
35 | * @param LoggerInterface $logger |
||
36 | */ |
||
37 | 34 | public function __construct( |
|
46 | |||
47 | /** |
||
48 | * @return PheanstalkInterface |
||
49 | * |
||
50 | * @deprecated Removed in next major version |
||
51 | */ |
||
52 | public function getPheanstalk() |
||
56 | |||
57 | /** |
||
58 | * @return LoggerInterface |
||
59 | * |
||
60 | * @deprecated Removed in next major version |
||
61 | */ |
||
62 | public function getLogger() |
||
66 | |||
67 | /** |
||
68 | * @param int $defaultTtr |
||
69 | * |
||
70 | * @return $this |
||
71 | */ |
||
72 | public function setDefaultTtr($defaultTtr) |
||
78 | |||
79 | /** |
||
80 | * @param string $action |
||
81 | * |
||
82 | * @throws Exception |
||
83 | * |
||
84 | * @return array |
||
85 | */ |
||
86 | 3 | View Code Duplication | public function getActionStats($action) |
98 | |||
99 | /** |
||
100 | * Add a job to the queue. |
||
101 | * |
||
102 | * @param string $action The action |
||
103 | * @param array $payload The job's payload |
||
104 | * @param string|int $delay The delay after which the job can be reserved. |
||
105 | * Can be a number of seconds, or a date-diff |
||
106 | * string relative from now, like "10 seconds". |
||
107 | * @param int $priority From 0 (most urgent) to 0xFFFFFFFF (least urgent) |
||
108 | * @param int $ttr Time To Run: seconds a job can be reserved for |
||
109 | * |
||
110 | * @throws InvalidArgumentException When the action is not defined |
||
111 | * @throws InvalidArgumentException When `$delay` or `$priority` is negative |
||
112 | * |
||
113 | * @return int The job id |
||
114 | */ |
||
115 | 9 | View Code Duplication | public function add($action, array $payload, $delay = null, $priority = null, $ttr = null) |
171 | |||
172 | /** |
||
173 | * Adds a job to the queue for an object. |
||
174 | * |
||
175 | * @param string $action The action |
||
176 | * @param object $object The object to add a job for |
||
177 | * @param string|int $delay The delay after which the job can be reserved. |
||
178 | * Can be a number of seconds, or a date-diff |
||
179 | * string relative from now, like "10 seconds". |
||
180 | * @param int $priority From 0 (most urgent) to 0xFFFFFFFF (least urgent) |
||
181 | * @param int $ttr Time To Run: seconds a job can be reserved for |
||
182 | * |
||
183 | * @throws \LogicException If the executor does not accepts objects as payloads |
||
184 | * @throws InvalidArgumentException If the executor does not accept the given object |
||
185 | * @throws InvalidArgumentException When the action is not defined |
||
186 | * |
||
187 | * @return int The job id |
||
188 | */ |
||
189 | 4 | View Code Duplication | public function addForObject($action, $object, $delay = null, $priority = null, $ttr = null) |
217 | |||
218 | /** |
||
219 | * Reschedules a job. |
||
220 | * |
||
221 | * @param Job $job |
||
222 | * @param \DateTime $date |
||
223 | * @param integer $priority |
||
224 | * |
||
225 | * @throws InvalidArgumentException When `$date` is in the past |
||
226 | */ |
||
227 | 3 | View Code Duplication | public function reschedule(Job $job, \DateTime $date, $priority = PheanstalkInterface::DEFAULT_PRIORITY) |
243 | |||
244 | /** |
||
245 | * @param string|string[] $actions |
||
246 | */ |
||
247 | 3 | View Code Duplication | public function watch($actions) |
259 | |||
260 | /** |
||
261 | * @param string|string[] $actions |
||
262 | */ |
||
263 | 1 | public function watchOnly($actions) |
|
270 | |||
271 | /** |
||
272 | * @param string|string[] $actions |
||
273 | */ |
||
274 | 2 | View Code Duplication | public function ignore($actions) |
286 | |||
287 | /** |
||
288 | * @param int $timeout |
||
289 | * |
||
290 | * @return Job|bool A job if there is one, false otherwise |
||
291 | */ |
||
292 | 2 | public function get($timeout = null) |
|
296 | |||
297 | /** |
||
298 | * Inspects the next job from the queue. Note that this does not reserve |
||
299 | * the job, so it will still be given to a worker if/once it's ready. |
||
300 | * |
||
301 | * @param string $action The action to peek |
||
302 | * @param string $state The state to peek for, can be 'ready', 'delayed' or 'buried' |
||
303 | * |
||
304 | * @throws InvalidArgumentException When $action is not a defined action |
||
305 | * @throws InvalidArgumentException When $state is not a valid state |
||
306 | * @throws Exception When Pheanstalk decides to do this |
||
307 | * |
||
308 | * @return Job The next job for the given state, or null if there is no next job |
||
309 | */ |
||
310 | 6 | View Code Duplication | public function peek($action, $state = 'ready') |
341 | |||
342 | /** |
||
343 | * Permanently deletes a job. |
||
344 | * |
||
345 | * @param Job $job |
||
346 | */ |
||
347 | 2 | public function delete(Job $job) |
|
353 | |||
354 | /** |
||
355 | * Puts a job into a 'buried' state, revived only by 'kick' command. |
||
356 | * |
||
357 | * @param Job $job |
||
358 | */ |
||
359 | 1 | public function bury(Job $job) |
|
365 | |||
366 | /** |
||
367 | * Puts a job into a 'buried' state, revived only by 'kick' command. |
||
368 | * |
||
369 | * @param string $action |
||
370 | * @param int $max |
||
371 | * |
||
372 | * @return int The number of kicked jobs |
||
373 | */ |
||
374 | 1 | View Code Duplication | public function kick($action, $max) |
386 | |||
387 | /** |
||
388 | * @param Job $job |
||
389 | * |
||
390 | * @return array |
||
391 | */ |
||
392 | 1 | public function getJobStats(Job $job) |
|
396 | |||
397 | /** |
||
398 | * CAUTION: this removes all items from an action's queue. |
||
399 | * This is an irreversible action! |
||
400 | * |
||
401 | * @param string $action |
||
402 | * @param array $states |
||
403 | */ |
||
404 | 2 | View Code Duplication | public function clear($action, array $states = []) |
414 | |||
415 | /** |
||
416 | * @param string $tube |
||
417 | * @param string $state |
||
418 | * |
||
419 | * @throws Exception |
||
420 | */ |
||
421 | 2 | View Code Duplication | protected function clearTube($tube, $state = 'ready') |
436 | |||
437 | /** |
||
438 | * @param int $jobId |
||
439 | * @param string $msg |
||
440 | * @param string $level |
||
441 | * @param array $context |
||
442 | */ |
||
443 | 10 | private function logJob($jobId, $msg, $level = LogLevel::DEBUG, array $context = []) |
|
447 | } |
||
448 |
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.