Complex classes like Client 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 Client, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 25 | class Client extends AbstractClient implements ClientInterface |
||
| 26 | { |
||
| 27 | protected $socket; |
||
| 28 | protected $chunk_size; |
||
| 29 | protected $verify_peer_name; |
||
| 30 | |||
| 31 | public function __construct(array $config, ObjectSpec $objectSpec = null) |
||
| 32 | { |
||
| 33 | parent::__construct($config, $objectSpec); |
||
| 34 | |||
| 35 | $this->chunk_size = (int) $this->getConfigDefault($config, 'chunk_size', 1024); |
||
| 36 | $this->verify_peer_name = $this->getConfigDefaultBool($config, 'verify_peer_name', true); |
||
| 37 | |||
| 38 | // override 'port' default to false from AbstractClient::prepareConnectionOptions |
||
| 39 | $this->port = (int) $this->getConfigDefault($config, 'port', 700); |
||
| 40 | } |
||
| 41 | |||
| 42 | public function __destruct() |
||
| 43 | { |
||
| 44 | $this->close(); |
||
| 45 | } |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Setup context in case of ssl connection |
||
| 49 | * |
||
| 50 | * @return resource|null |
||
| 51 | */ |
||
| 52 | private function setupContext() |
||
| 53 | { |
||
| 54 | if (!$this->ssl) { |
||
| 55 | return null; |
||
| 56 | } |
||
| 57 | |||
| 58 | $context = stream_context_create(); |
||
| 59 | |||
| 60 | $options_array = [ |
||
| 61 | 'verify_peer' => false, |
||
| 62 | 'verify_peer_name' => $this->verify_peer_name, |
||
| 63 | 'allow_self_signed' => true, |
||
| 64 | 'local_cert' => $this->local_cert, |
||
| 65 | 'passphrase' => $this->passphrase, |
||
| 66 | 'cafile' => $this->ca_cert, |
||
| 67 | 'local_pk' => $this->pk_cert, |
||
| 68 | ]; |
||
| 69 | |||
| 70 | // filter out empty user provided values |
||
| 71 | $options_array = array_filter( |
||
| 72 | $options_array, |
||
| 73 | function ($var) { |
||
| 74 | return !is_null($var); |
||
| 75 | } |
||
| 76 | ); |
||
| 77 | |||
| 78 | $options = ['ssl' => $options_array]; |
||
| 79 | |||
| 80 | // stream_context_set_option accepts array of options in form of $arr['wrapper']['option'] = value |
||
| 81 | stream_context_set_option($context, $options); |
||
| 82 | |||
| 83 | return $context; |
||
| 84 | } |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Setup connection socket |
||
| 88 | * |
||
| 89 | * @param resource|null $context SSL context or null in case of tcp connection |
||
| 90 | * |
||
| 91 | * @throws Exception on socket errors |
||
| 92 | */ |
||
| 93 | private function setupSocket($context = null) |
||
| 94 | { |
||
| 95 | $proto = $this->ssl ? 'ssl' : 'tcp'; |
||
| 96 | $target = sprintf('%s://%s:%d', $proto, $this->host, $this->port); |
||
| 97 | |||
| 98 | $errno = 0; |
||
| 99 | $errstr = ''; |
||
| 100 | |||
| 101 | $this->socket = @stream_socket_client($target, $errno, $errstr, $this->connect_timeout, STREAM_CLIENT_CONNECT, $context); |
||
| 102 | |||
| 103 | if ($this->socket === false) { |
||
| 104 | // Socket initialization may fail, before system call connect() |
||
| 105 | // so the $errno is 0 and $errstr isn't populated . |
||
| 106 | // see https://www.php.net/manual/en/function.stream-socket-client.php#refsect1-function.stream-socket-client-errors |
||
| 107 | throw new Exception(sprintf('problem initializing socket: %s code: [%d]', $errstr, $errno), $errno); |
||
| 108 | } |
||
| 109 | |||
| 110 | // set stream time out |
||
| 111 | if (!stream_set_timeout($this->socket, $this->timeout)) { |
||
| 112 | throw new Exception('unable to set stream timeout'); |
||
| 113 | } |
||
| 114 | |||
| 115 | // set to non-blocking |
||
| 116 | if (!stream_set_blocking($this->socket, 0)) { |
||
| 117 | throw new Exception('unable to set blocking'); |
||
| 118 | } |
||
| 119 | } |
||
| 120 | |||
| 121 | /** |
||
| 122 | * {@inheritdoc} |
||
| 123 | * |
||
| 124 | * @see \AfriCC\EPP\ClientInterface::connect() |
||
| 125 | */ |
||
| 126 | public function connect($newPassword = false) |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Closes a previously opened EPP connection |
||
| 143 | */ |
||
| 144 | public function close() |
||
| 155 | |||
| 156 | public function getFrame() |
||
| 157 | { |
||
| 158 | $hard_time_limit = time() + $this->timeout + 2; |
||
| 159 | do { |
||
| 179 | |||
| 180 | public function sendFrame(FrameInterface $frame) |
||
| 187 | |||
| 188 | protected function log($message, $color = '0;32') |
||
| 195 | |||
| 196 | /** |
||
| 197 | * check if socket is still active |
||
| 198 | * |
||
| 199 | * @return bool |
||
| 200 | */ |
||
| 201 | private function active() |
||
| 205 | |||
| 206 | /** |
||
| 207 | * receive socket data |
||
| 208 | * |
||
| 209 | * @param int $length |
||
| 210 | * |
||
| 211 | * @throws Exception |
||
| 212 | * |
||
| 213 | * @return string |
||
| 214 | */ |
||
| 215 | private function recv($length) |
||
| 254 | |||
| 255 | /** |
||
| 256 | * send data to socket |
||
| 257 | * |
||
| 258 | * @param string $buffer |
||
| 259 | */ |
||
| 260 | private function send($buffer) |
||
| 312 | } |
||
| 313 |