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  | 
            ||
| 14 | abstract class Task { | 
            ||
| 15 | |||
| 16 | const LOCK_DIR = '/tmp';  | 
            ||
| 17 | const PS_EXEC = 'ps --no-heading -p ';  | 
            ||
| 18 | |||
| 19 | abstract public function run( array $args );  | 
            ||
| 20 | |||
| 21 | 	public function __invoke() { | 
            ||
| 22 | |||
| 23 | if( !$this->lock() )  | 
            ||
| 24 | 			throw new \RuntimeException(sprintf('An instance of \\%s is already running', get_class($this))); | 
            ||
| 25 | |||
| 26 | $result = $this->run(  | 
            ||
| 27 | $this->parseArgs()  | 
            ||
| 28 | );  | 
            ||
| 29 | |||
| 30 | $this->unlock();  | 
            ||
| 31 | |||
| 32 | return $result;  | 
            ||
| 33 | |||
| 34 | }  | 
            ||
| 35 | |||
| 36 | /**  | 
            ||
| 37 | * parseArgs Command Line Interface (CLI) utility function.  | 
            ||
| 38 | * @author Patrick Fisher <[email protected]>  | 
            ||
| 39 | * @see https://github.com/pwfisher/CommandLine.php  | 
            ||
| 40 | */  | 
            ||
| 41 | 	protected function parseArgs( $argv = null ) { | 
            ||
| 42 | $argv = $argv ? $argv : $_SERVER['argv']; array_shift($argv); $o = [];  | 
            ||
| 43 | 		for ($i = 0, $j = count($argv); $i < $j; $i++) { $a = $argv[$i]; | 
            ||
| 44 | 			if (substr($a, 0, 2) == '--') { $eq = strpos($a, '='); | 
            ||
| 45 | 				if ($eq !== false) { $o[substr($a, 2, $eq - 2)] = substr($a, $eq + 1); } | 
            ||
| 46 | View Code Duplication | 				else { $k = substr($a, 2); | 
            |
| 47 | 					if ($i + 1 < $j && $argv[$i + 1][0] !== '-') { $o[$k] = $argv[$i + 1]; $i++; } | 
            ||
| 48 | 					else if (!isset($o[$k])) { $o[$k] = true; } } } | 
            ||
| 49 | 			else if (substr($a, 0, 1) == '-') { | 
            ||
| 50 | 				if (substr($a, 2, 1) == '=') { $o[substr($a, 1, 1)] = substr($a, 3); } | 
            ||
| 51 | View Code Duplication | 				else { | 
            |
| 52 | 					foreach (str_split(substr($a, 1)) as $k) { if (!isset($o[$k])) { $o[$k] = true; } } | 
            ||
| 53 | 					if ($i + 1 < $j && $argv[$i + 1][0] !== '-') { $o[$k] = $argv[$i + 1]; $i++; } } } | 
            ||
| 54 | 			else { $o[] = $a; } } | 
            ||
| 55 | return $o;  | 
            ||
| 56 | }  | 
            ||
| 57 | |||
| 58 | /**  | 
            ||
| 59 | * Return the name of the lock file used by this task.  | 
            ||
| 60 | * @return string  | 
            ||
| 61 | */  | 
            ||
| 62 | 	protected function getLockFile() { | 
            ||
| 65 | |||
| 66 | 	protected function isLocked() { | 
            ||
| 67 | |||
| 68 | // check if lock file exists  | 
            ||
| 69 | $locked = file_exists($lock = $this->getLockFile());  | 
            ||
| 70 | |||
| 71 | // if it does then check the process is actually still running  | 
            ||
| 72 | 		if( $locked ) { | 
            ||
| 73 | $pid = file_get_contents($lock);  | 
            ||
| 74 | $locked = exec(static::PS_EXEC. $pid) != '';  | 
            ||
| 75 | // no such process so remove the lock file  | 
            ||
| 76 | if( !$locked )  | 
            ||
| 77 | $this->unlock();  | 
            ||
| 78 | }  | 
            ||
| 79 | |||
| 80 | return $locked;  | 
            ||
| 81 | |||
| 82 | }  | 
            ||
| 83 | |||
| 84 | 	protected function lock() { | 
            ||
| 85 | |||
| 86 | // locked by running process  | 
            ||
| 87 | if( $this->isLocked() )  | 
            ||
| 88 | return false;  | 
            ||
| 89 | |||
| 90 | // open the lock file only if it doesn't exist  | 
            ||
| 91 | if( !$fh = @fopen($this->getLockFile(), 'x') )  | 
            ||
| 92 | return false;  | 
            ||
| 93 | |||
| 94 | // clear it and write out the new PID  | 
            ||
| 95 | ftruncate($fh, 0);  | 
            ||
| 96 | fwrite($fh, getmypid());  | 
            ||
| 97 | fclose($fh);  | 
            ||
| 98 | |||
| 99 | return true;  | 
            ||
| 100 | |||
| 101 | }  | 
            ||
| 102 | |||
| 103 | 	protected function unlock() { | 
            ||
| 120 | |||
| 121 | }  | 
            ||
| 122 | |||
| 123 | // EOF  |