Complex classes like Connector 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 Connector, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class Connector { |
||
| 20 | |||
| 21 | const SERVER_PROTOCOL = 5; |
||
| 22 | const SERVER_COOKIE = 'php-console-server'; |
||
| 23 | const CLIENT_INFO_COOKIE = 'php-console-client'; |
||
| 24 | const CLIENT_ENCODING = 'UTF-8'; |
||
| 25 | const HEADER_NAME = 'PHP-Console'; |
||
| 26 | const POSTPONE_HEADER_NAME = 'PHP-Console-Postpone'; |
||
| 27 | const POST_VAR_NAME = '__PHP_Console'; |
||
| 28 | const POSTPONE_REQUESTS_LIMIT = 10; |
||
| 29 | const PHP_HEADERS_SIZE = 1000; // maximum PHP response headers size |
||
| 30 | const CLIENT_HEADERS_LIMIT = 200000; |
||
| 31 | |||
| 32 | /** @var Connector */ |
||
| 33 | protected static $instance; |
||
| 34 | /** @var Storage|null */ |
||
| 35 | private static $postponeStorage; |
||
| 36 | |||
| 37 | /** @var Dumper|null */ |
||
| 38 | protected $dumper; |
||
| 39 | /** @var Dispatcher\Debug|null */ |
||
| 40 | protected $debugDispatcher; |
||
| 41 | /** @var Dispatcher\Errors|null */ |
||
| 42 | protected $errorsDispatcher; |
||
| 43 | /** @var Dispatcher\Evaluate|null */ |
||
| 44 | protected $evalDispatcher; |
||
| 45 | /** @var string */ |
||
| 46 | protected $serverEncoding = self::CLIENT_ENCODING; |
||
| 47 | protected $sourcesBasePath; |
||
| 48 | protected $headersLimit; |
||
| 49 | |||
| 50 | /** @var Client|null */ |
||
| 51 | private $client; |
||
| 52 | /** @var Auth|null */ |
||
| 53 | private $auth; |
||
| 54 | /** @var Message[] */ |
||
| 55 | private $messages = array(); |
||
| 56 | private $postponeResponseId; |
||
| 57 | private $isSslOnlyMode = false; |
||
| 58 | private $isActiveClient = false; |
||
| 59 | private $isAuthorized = false; |
||
| 60 | private $isEvalListenerStarted = false; |
||
| 61 | private $registeredShutDowns = 0; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @return static |
||
| 65 | */ |
||
| 66 | public static function getInstance() { |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Set storage for postponed response data. Storage\Session is used by default, but if you have problems with overridden session handler you should use another one. |
||
| 75 | * IMPORTANT: This method cannot be called after Connector::getInstance() |
||
| 76 | * @param Storage $storage |
||
| 77 | * @throws \Exception |
||
| 78 | */ |
||
| 79 | public static function setPostponeStorage(Storage $storage) { |
||
| 85 | |||
| 86 | /** |
||
| 87 | * @return Storage |
||
| 88 | */ |
||
| 89 | private function getPostponeStorage() { |
||
| 95 | |||
| 96 | protected function __construct() { |
||
| 100 | |||
| 101 | private final function __clone() { |
||
| 103 | |||
| 104 | /** |
||
| 105 | * Detect script is running in command-line mode |
||
| 106 | * @return int |
||
| 107 | */ |
||
| 108 | protected function isCliMode() { |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Notify clients that there is active PHP Console on server & check if there is request from client with active PHP Console |
||
| 114 | * @throws \Exception |
||
| 115 | */ |
||
| 116 | private function initConnection() { |
||
| 136 | |||
| 137 | /** |
||
| 138 | * Get connected client data( |
||
| 139 | * @return Client|null |
||
| 140 | * @throws \Exception |
||
| 141 | */ |
||
| 142 | private function initClient() { |
||
| 156 | |||
| 157 | /** |
||
| 158 | * Notify clients that there is active PHP Console on server |
||
| 159 | * @throws \Exception |
||
| 160 | */ |
||
| 161 | private function initServerCookie() { |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Check if there is client is installed PHP Console extension |
||
| 172 | * @return bool |
||
| 173 | */ |
||
| 174 | public function isActiveClient() { |
||
| 177 | |||
| 178 | /** |
||
| 179 | * Set client connection as not active |
||
| 180 | */ |
||
| 181 | public function disable() { |
||
| 184 | |||
| 185 | /** |
||
| 186 | * Check if client with valid auth credentials is connected |
||
| 187 | * @return bool |
||
| 188 | */ |
||
| 189 | public function isAuthorized() { |
||
| 192 | |||
| 193 | /** |
||
| 194 | * Set IP masks of clients that will be allowed to connect to PHP Console |
||
| 195 | * @param array $ipMasks Use *(star character) for "any numbers" placeholder array('192.168.*.*', '10.2.12*.*', '127.0.0.1', '2001:0:5ef5:79fb:*:*:*:*') |
||
| 196 | */ |
||
| 197 | public function setAllowedIpMasks(array $ipMasks) { |
||
| 210 | |||
| 211 | /** |
||
| 212 | * @return Dumper |
||
| 213 | */ |
||
| 214 | public function getDumper() { |
||
| 220 | |||
| 221 | /** |
||
| 222 | * Override default errors dispatcher |
||
| 223 | * @param Dispatcher\Errors $dispatcher |
||
| 224 | */ |
||
| 225 | public function setErrorsDispatcher(Dispatcher\Errors $dispatcher) { |
||
| 228 | |||
| 229 | /** |
||
| 230 | * Get dispatcher responsible for sending errors/exceptions messages |
||
| 231 | * @return Dispatcher\Errors |
||
| 232 | */ |
||
| 233 | public function getErrorsDispatcher() { |
||
| 239 | |||
| 240 | /** |
||
| 241 | * Override default debug dispatcher |
||
| 242 | * @param Dispatcher\Debug $dispatcher |
||
| 243 | */ |
||
| 244 | public function setDebugDispatcher(Dispatcher\Debug $dispatcher) { |
||
| 247 | |||
| 248 | /** |
||
| 249 | * Get dispatcher responsible for sending debug messages |
||
| 250 | * @return Dispatcher\Debug |
||
| 251 | */ |
||
| 252 | public function getDebugDispatcher() { |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Override default eval requests dispatcher |
||
| 261 | * @param Dispatcher\Evaluate $dispatcher |
||
| 262 | */ |
||
| 263 | public function setEvalDispatcher(Dispatcher\Evaluate $dispatcher) { |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Get dispatcher responsible for handling eval requests |
||
| 269 | * @return Dispatcher\Evaluate |
||
| 270 | */ |
||
| 271 | public function getEvalDispatcher() { |
||
| 277 | |||
| 278 | /** |
||
| 279 | * Enable eval request to be handled by eval dispatcher. Must be called after all Connector configurations. |
||
| 280 | * Connector::getInstance()->setPassword() is required to be called before this method |
||
| 281 | * Use Connector::getInstance()->setAllowedIpMasks() for additional access protection |
||
| 282 | * Check Connector::getInstance()->getEvalDispatcher()->getEvalProvider() to customize eval accessibility & security options |
||
| 283 | * @param bool $exitOnEval |
||
| 284 | * @param bool $flushDebugMessages Clear debug messages handled before this method is called |
||
| 285 | * @throws \Exception |
||
| 286 | */ |
||
| 287 | public function startEvalRequestsListener($exitOnEval = true, $flushDebugMessages = true) { |
||
| 318 | |||
| 319 | /** |
||
| 320 | * Set bath to base dir of project source code(so it will be stripped in paths displaying on client) |
||
| 321 | * @param $sourcesBasePath |
||
| 322 | * @throws \Exception |
||
| 323 | */ |
||
| 324 | public function setSourcesBasePath($sourcesBasePath) { |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Protect PHP Console connection by password |
||
| 334 | * |
||
| 335 | * Use Connector::getInstance()->setAllowedIpMasks() for additional secure |
||
| 336 | * @param string $password |
||
| 337 | * @param bool $publicKeyByIp Set authorization token depending on client IP |
||
| 338 | * @throws \Exception |
||
| 339 | */ |
||
| 340 | public function setPassword($password, $publicKeyByIp = true) { |
||
| 350 | |||
| 351 | /** |
||
| 352 | * Encode var to JSON with errors & encoding handling |
||
| 353 | * @param $var |
||
| 354 | * @return string |
||
| 355 | * @throws \Exception |
||
| 356 | */ |
||
| 357 | protected function jsonEncode($var) { |
||
| 360 | |||
| 361 | /** |
||
| 362 | * Recursive var data encoding conversion |
||
| 363 | * @param $data |
||
| 364 | * @param $fromEncoding |
||
| 365 | * @param $toEncoding |
||
| 366 | */ |
||
| 367 | protected function convertArrayEncoding(&$data, $toEncoding, $fromEncoding) { |
||
| 370 | |||
| 371 | /** |
||
| 372 | * Encoding conversion callback for array_walk_recursive() |
||
| 373 | * @param string $string |
||
| 374 | * @param null $key |
||
| 375 | * @param array $args |
||
| 376 | */ |
||
| 377 | protected function convertWalkRecursiveItemEncoding(&$string, $key = null, array $args) { |
||
| 380 | |||
| 381 | /** |
||
| 382 | * Convert string encoding |
||
| 383 | * @param string $string |
||
| 384 | * @param string $toEncoding |
||
| 385 | * @param string|null $fromEncoding |
||
| 386 | * @throws \Exception |
||
| 387 | */ |
||
| 388 | protected function convertEncoding(&$string, $toEncoding, $fromEncoding) { |
||
| 405 | |||
| 406 | /** |
||
| 407 | * Set headers size limit for your web-server. You can auto-detect headers size limit by /examples/utils/detect_headers_limit.php |
||
| 408 | * @param $bytes |
||
| 409 | * @throws \Exception |
||
| 410 | */ |
||
| 411 | public function setHeadersLimit($bytes) { |
||
| 418 | |||
| 419 | /** |
||
| 420 | * Set your server PHP internal encoding, if it's different from "mbstring.internal_encoding" or UTF-8 |
||
| 421 | * @param $encoding |
||
| 422 | */ |
||
| 423 | public function setServerEncoding($encoding) { |
||
| 429 | |||
| 430 | /** |
||
| 431 | * Send data message to PHP Console client(if it's connected) |
||
| 432 | * @param Message $message |
||
| 433 | */ |
||
| 434 | public function sendMessage(Message $message) { |
||
| 439 | |||
| 440 | /** |
||
| 441 | * Register shut down callback handler. Must be called after all errors handlers register_shutdown_function() |
||
| 442 | */ |
||
| 443 | public function registerFlushOnShutDown() { |
||
| 447 | |||
| 448 | /** |
||
| 449 | * This method must be called only by register_shutdown_function(). Never call it manually! |
||
| 450 | */ |
||
| 451 | public function onShutDown() { |
||
| 457 | |||
| 458 | /** |
||
| 459 | * Force connection by SSL for clients with PHP Console installed |
||
| 460 | */ |
||
| 461 | public function enableSslOnlyMode() { |
||
| 464 | |||
| 465 | /** |
||
| 466 | * Check if client is connected by SSL |
||
| 467 | * @return bool |
||
| 468 | */ |
||
| 469 | protected function isSsl() { |
||
| 472 | |||
| 473 | /** |
||
| 474 | * Send response data to client |
||
| 475 | * @throws \Exception |
||
| 476 | */ |
||
| 477 | private function proceedResponsePackage() { |
||
| 478 | if($this->isActiveClient()) { |
||
| 479 | $response = new Response(); |
||
| 480 | $response->isSslOnlyMode = $this->isSslOnlyMode; |
||
| 481 | |||
| 482 | if(isset($_POST[self::POST_VAR_NAME]['getBackData'])) { |
||
| 483 | $response->getBackData = $_POST[self::POST_VAR_NAME]['getBackData']; |
||
| 484 | } |
||
| 485 | |||
| 486 | if(!$this->isSslOnlyMode || $this->isSsl()) { |
||
| 487 | if($this->auth) { |
||
| 488 | $response->auth = $this->auth->getServerAuthStatus($this->client->auth); |
||
| 489 | } |
||
| 490 | if(!$this->auth || $this->isAuthorized()) { |
||
| 491 | $response->isLocal = isset($_SERVER['REMOTE_ADDR']) && ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1'); |
||
| 492 | $response->docRoot = isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : null; |
||
| 493 | $response->sourcesBasePath = $this->sourcesBasePath; |
||
| 494 | $response->isEvalEnabled = $this->isEvalListenerStarted; |
||
| 495 | $response->messages = $this->messages; |
||
| 496 | } |
||
| 497 | } |
||
| 498 | |||
| 499 | $responseData = $this->serializeResponse($response); |
||
| 500 | |||
| 501 | if(strlen($responseData) > $this->headersLimit || !$this->setHeaderData($responseData, self::HEADER_NAME, false)) { |
||
| 502 | $this->getPostponeStorage()->push($this->postponeResponseId, $responseData); |
||
| 503 | } |
||
| 504 | } |
||
| 505 | } |
||
| 506 | |||
| 507 | private function setPostponeHeader() { |
||
| 516 | |||
| 517 | private function setHeaderData($responseData, $headerName, $throwException = true) { |
||
| 527 | |||
| 528 | protected function objectToArray(&$var) { |
||
| 534 | |||
| 535 | protected function serializeResponse(DataObject $response) { |
||
| 542 | |||
| 543 | /** |
||
| 544 | * Check if there is postponed response request and dispatch it |
||
| 545 | */ |
||
| 546 | private function listenGetPostponedResponse() { |
||
| 554 | } |
||
| 555 | |||
| 646 |