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 Worker 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 Worker, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class Worker extends Generic |
||
| 20 | { |
||
| 21 | |||
| 22 | /** |
||
| 23 | * Update? |
||
| 24 | * @var boolean |
||
| 25 | */ |
||
| 26 | public $update = false; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * Reload? |
||
| 30 | * @var boolean |
||
| 31 | */ |
||
| 32 | public $reload = false; |
||
| 33 | |||
| 34 | protected $graceful = false; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Reload delay |
||
| 38 | * @var integer |
||
| 39 | */ |
||
| 40 | protected $reloadDelay = 2; |
||
| 41 | |||
| 42 | /** |
||
| 43 | * Reloaded? |
||
| 44 | * @var boolean |
||
| 45 | */ |
||
| 46 | public $reloaded = false; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Time of last activity |
||
| 50 | * @var integer |
||
| 51 | */ |
||
| 52 | public $timeLastActivity = 0; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Last time of auto reload |
||
| 56 | * @var integer |
||
| 57 | */ |
||
| 58 | protected $autoReloadLast = 0; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * State |
||
| 62 | * @var integer |
||
| 63 | */ |
||
| 64 | public $state = 0; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Request counter |
||
| 68 | * @var integer |
||
| 69 | */ |
||
| 70 | public $reqCounter = 0; |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Break main loop? |
||
| 74 | * @var boolean |
||
| 75 | */ |
||
| 76 | public $breakMainLoop = false; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * Reload ready? |
||
| 80 | * @var boolean |
||
| 81 | */ |
||
| 82 | public $reloadReady = false; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * If true, we do not register signals automatically at start |
||
| 86 | * @var boolean |
||
| 87 | */ |
||
| 88 | protected $delayedSigReg = false; |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Instances count |
||
| 92 | * @var array |
||
| 93 | */ |
||
| 94 | public $instancesCount = []; |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Connection |
||
| 98 | * @var Connection |
||
| 99 | */ |
||
| 100 | public $connection; |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Counter GC |
||
| 104 | * @var integer |
||
| 105 | */ |
||
| 106 | public $counterGC = 0; |
||
| 107 | |||
| 108 | |||
| 109 | /** @var \PHPDaemon\IPCManager\IPCManager */ |
||
| 110 | public $IPCManager; |
||
| 111 | |||
| 112 | public $lambdaCache; |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Runtime of Worker process. |
||
| 116 | * @return void |
||
| 117 | */ |
||
| 118 | protected function run() |
||
| 119 | { |
||
| 120 | $this->lambdaCache = new CappedStorageHits; |
||
| 121 | $this->lambdaCache->setMaxCacheSize(Daemon::$config->lambdacachemaxsize->value); |
||
| 122 | $this->lambdaCache->setCapWindow(Daemon::$config->lambdacachecapwindow->value); |
||
| 123 | |||
| 124 | if (Daemon::$process instanceof Master) { |
||
| 125 | Daemon::$process->unregisterSignals(); |
||
|
|
|||
| 126 | } |
||
| 127 | |||
| 128 | EventLoop::init(); |
||
| 129 | |||
| 130 | Daemon::$process = $this; |
||
| 131 | if (Daemon::$logpointerAsync) { |
||
| 132 | Daemon::$logpointerAsync->fd = null; |
||
| 133 | Daemon::$logpointerAsync = null; |
||
| 134 | } |
||
| 135 | class_exists('Timer'); |
||
| 136 | $this->autoReloadLast = time(); |
||
| 137 | $this->reloadDelay = Daemon::$config->mpmdelay->value + 2; |
||
| 138 | $this->setState(Daemon::WSTATE_PREINIT); |
||
| 139 | |||
| 140 | if (Daemon::$config->autogc->value > 0) { |
||
| 141 | gc_enable(); |
||
| 142 | gc_collect_cycles(); |
||
| 143 | } else { |
||
| 144 | gc_disable(); |
||
| 145 | } |
||
| 146 | |||
| 147 | if (Daemon::$runworkerMode) { |
||
| 148 | View Code Duplication | if (!Daemon::$config->verbosetty->value) { |
|
| 149 | fclose(STDIN); |
||
| 150 | fclose(STDOUT); |
||
| 151 | fclose(STDERR); |
||
| 152 | } |
||
| 153 | |||
| 154 | Daemon::$appResolver->preload(true); |
||
| 155 | } |
||
| 156 | |||
| 157 | $this->prepareSystemEnv(); |
||
| 158 | $this->overrideNativeFuncs(); |
||
| 159 | |||
| 160 | $this->setState(Daemon::WSTATE_INIT); |
||
| 161 | $this->registerEventSignals(); |
||
| 162 | |||
| 163 | FileSystem::init(); |
||
| 164 | FileSystem::initEvent(); |
||
| 165 | Daemon::openLogs(); |
||
| 166 | |||
| 167 | $this->IPCManager = Daemon::$appResolver->getInstanceByAppName('\PHPDaemon\IPCManager\IPCManager'); |
||
| 168 | if (!$this->IPCManager) { |
||
| 169 | $this->log('cannot instantiate IPCManager'); |
||
| 170 | } |
||
| 171 | |||
| 172 | Daemon::$appResolver->preload(); |
||
| 173 | |||
| 174 | foreach (Daemon::$appInstances as $app) { |
||
| 175 | foreach ($app as $appInstance) { |
||
| 176 | if (!$appInstance->ready) { |
||
| 177 | $appInstance->ready = true; |
||
| 178 | $appInstance->onReady(); |
||
| 179 | } |
||
| 180 | } |
||
| 181 | } |
||
| 182 | |||
| 183 | $this->setState(Daemon::WSTATE_IDLE); |
||
| 184 | |||
| 185 | Timer::add(function ($event) { |
||
| 186 | |||
| 187 | if (!Daemon::$runworkerMode) { |
||
| 188 | if ($this->IPCManager) { |
||
| 189 | $this->IPCManager->ensureConnection(); |
||
| 190 | } |
||
| 191 | } |
||
| 192 | |||
| 193 | $this->breakMainLoopCheck(); |
||
| 194 | if (Daemon::checkAutoGC()) { |
||
| 195 | EventLoop::$instance->interrupt(function () { |
||
| 196 | gc_collect_cycles(); |
||
| 197 | }); |
||
| 198 | } |
||
| 199 | |||
| 200 | $event->timeout(); |
||
| 201 | }, 1e6 * 1, 'breakMainLoopCheck'); |
||
| 202 | if (Daemon::$config->autoreload->value > 0) { |
||
| 203 | Timer::add(function ($event) { |
||
| 204 | static $n = 0; |
||
| 205 | $list = get_included_files(); |
||
| 206 | $s = sizeof($list); |
||
| 207 | if ($s > $n) { |
||
| 208 | $slice = array_map('realpath', array_slice($list, $n)); |
||
| 209 | Daemon::$process->IPCManager->sendPacket(['op' => 'addIncludedFiles', 'files' => $slice]); |
||
| 210 | $n = $s; |
||
| 211 | } |
||
| 212 | $event->timeout(); |
||
| 213 | }, 1e6 * Daemon::$config->autoreload->value, 'watchIncludedFiles'); |
||
| 214 | } |
||
| 215 | EventLoop::$instance->run(); |
||
| 216 | $this->shutdown(); |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Override a standard PHP function |
||
| 221 | * @param string $local e.g. isUploadedFile |
||
| 222 | * @param string $real e.g. is_uploaded_file |
||
| 223 | */ |
||
| 224 | protected function override($camelCase, $real) |
||
| 225 | { |
||
| 226 | runkit_function_rename($real, $real . '_native'); |
||
| 227 | runkit_function_rename('PHPDaemon\\Thread\\' . $camelCase, $real); |
||
| 228 | } |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Overrides native PHP functions. |
||
| 232 | * @return void |
||
| 233 | */ |
||
| 234 | protected function overrideNativeFuncs() |
||
| 235 | { |
||
| 236 | if (Daemon::supported(Daemon::SUPPORT_RUNKIT_INTERNAL_MODIFY)) { |
||
| 237 | function define($k, $v) |
||
| 245 | |||
| 246 | $this->override('define', 'define'); |
||
| 247 | |||
| 248 | function header(...$args) |
||
| 255 | |||
| 256 | $this->override('header', 'header'); |
||
| 257 | |||
| 258 | function isUploadedFile(...$args) |
||
| 265 | |||
| 266 | $this->override('isUploadedFile', 'is_uploaded_file'); |
||
| 267 | |||
| 268 | function moveUploadedFile(...$args) |
||
| 275 | |||
| 276 | $this->override('moveUploadedFile', 'move_uploaded_file'); |
||
| 277 | |||
| 278 | function headersSent(&$file = null, &$line = null) |
||
| 285 | |||
| 286 | //$this->override('headersSent', 'headers_sent); // Commented out due to a runkit bug |
||
| 287 | |||
| 288 | function headersList() |
||
| 295 | |||
| 296 | $this->override('headersList', 'headers_list'); |
||
| 297 | |||
| 298 | function setcookie(...$args) |
||
| 305 | |||
| 306 | $this->override('setcookie', 'setcookie'); |
||
| 307 | |||
| 308 | /** |
||
| 309 | * @param callable $cb |
||
| 310 | */ |
||
| 311 | function registerShutdownFunction($cb) |
||
| 318 | |||
| 319 | $this->override('registerShutdownFunction', 'register_shutdown_function'); |
||
| 320 | |||
| 326 | |||
| 327 | /** |
||
| 328 | * Creates anonymous function (old-fashioned) like create_function() |
||
| 329 | * @return void |
||
| 330 | */ |
||
| 331 | public function createFunction($args, $body, $ttl = null) |
||
| 344 | |||
| 345 | /** |
||
| 346 | * Setup settings on start. |
||
| 347 | * @return void |
||
| 348 | */ |
||
| 349 | protected function prepareSystemEnv() |
||
| 418 | |||
| 419 | /** |
||
| 420 | * Log something |
||
| 421 | * @param string - Message. |
||
| 422 | * @param string $message |
||
| 423 | * @return void |
||
| 424 | */ |
||
| 425 | public function log($message) |
||
| 429 | |||
| 430 | /** |
||
| 431 | * Reloads additional config-files on-the-fly. |
||
| 432 | * @return void |
||
| 433 | */ |
||
| 434 | protected function update() |
||
| 443 | |||
| 444 | /** |
||
| 445 | * Check if we should break main loop |
||
| 446 | * @return void |
||
| 447 | */ |
||
| 448 | protected function breakMainLoopCheck() |
||
| 495 | |||
| 496 | /** |
||
| 497 | * Graceful restart |
||
| 498 | * @return void |
||
| 499 | */ |
||
| 500 | View Code Duplication | public function gracefulRestart() |
|
| 509 | |||
| 510 | /** |
||
| 511 | * Graceful stop |
||
| 512 | * @return void |
||
| 513 | */ |
||
| 514 | View Code Duplication | public function gracefulStop() |
|
| 522 | |||
| 523 | /** |
||
| 524 | * Asks the running applications the whether we can go to shutdown current (old) worker. |
||
| 525 | * @return boolean - Ready? |
||
| 526 | */ |
||
| 527 | protected function appInstancesReloadReady() |
||
| 541 | |||
| 542 | /** |
||
| 543 | * Shutdown this worker |
||
| 544 | * @param boolean Hard? If hard, we shouldn't wait for graceful shutdown of the running applications. |
||
| 545 | * @return boolean|null Ready? |
||
| 546 | */ |
||
| 547 | protected function shutdown($hard = false) |
||
| 601 | |||
| 602 | /** |
||
| 603 | * Set current status of worker |
||
| 604 | * @param int Constant |
||
| 605 | * @return boolean Success. |
||
| 606 | */ |
||
| 607 | public function setState($int) |
||
| 630 | |||
| 631 | /** |
||
| 632 | * Handler of the SIGINT (hard shutdown) signal in worker process. |
||
| 633 | * @return void |
||
| 634 | */ |
||
| 635 | protected function sigint() |
||
| 643 | |||
| 644 | /** |
||
| 645 | * Handler of the SIGTERM (graceful shutdown) signal in worker process. |
||
| 646 | * @return void |
||
| 647 | */ |
||
| 648 | protected function sigterm() |
||
| 657 | |||
| 658 | /** |
||
| 659 | * Handler of the SIGQUIT (graceful shutdown) signal in worker process. |
||
| 660 | * @return void |
||
| 661 | */ |
||
| 662 | protected function sigquit() |
||
| 670 | |||
| 671 | /** |
||
| 672 | * Handler of the SIGHUP (reload config) signal in worker process. |
||
| 673 | * @return void |
||
| 674 | */ |
||
| 675 | View Code Duplication | protected function sighup() |
|
| 687 | |||
| 688 | /** |
||
| 689 | * Handler of the SIGUSR1 (re-open log-file) signal in worker process. |
||
| 690 | * @return void |
||
| 691 | */ |
||
| 692 | protected function sigusr1() |
||
| 700 | |||
| 701 | /** |
||
| 702 | * Handler of the SIGUSR2 (graceful shutdown for update) signal in worker process. |
||
| 703 | * @return void |
||
| 704 | */ |
||
| 705 | protected function sigusr2() |
||
| 713 | |||
| 714 | /** |
||
| 715 | * Handler of the SIGTSTP (graceful stop) signal in worker process. |
||
| 716 | * @return void |
||
| 717 | */ |
||
| 718 | protected function sigtstp() |
||
| 726 | |||
| 727 | /** |
||
| 728 | * Handler of the SIGTTIN signal in worker process. |
||
| 729 | * @return void |
||
| 730 | */ |
||
| 731 | protected function sigttin() |
||
| 734 | |||
| 735 | /** |
||
| 736 | * Handler of the SIGPIPE signal in worker process. |
||
| 737 | * @return void |
||
| 738 | */ |
||
| 739 | protected function sigpipe() |
||
| 742 | |||
| 743 | /** |
||
| 744 | * Handler of non-known signals. |
||
| 745 | * @return void |
||
| 746 | */ |
||
| 747 | View Code Duplication | protected function sigunknown($signo) |
|
| 757 | |||
| 758 | /** |
||
| 759 | * Called (in master) when process is terminated |
||
| 760 | * @return void |
||
| 761 | */ |
||
| 762 | public function onTerminated() |
||
| 766 | |||
| 767 | /** |
||
| 768 | * Destructor of worker thread. |
||
| 769 | * @return void |
||
| 770 | */ |
||
| 771 | public function __destruct() |
||
| 777 | } |
||
| 778 |
This check looks for access to methods that are not accessible from the current context.
If you need to make a method accessible to another context you can raise its visibility level in the defining class.