Complex classes like SmallFilesQueueTransport 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 SmallFilesQueueTransport, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 7 | class SmallFilesQueueTransport extends AbstractQueueTransport { |
||
| 8 | const SINGLE_FILE_DB_VERSION = 1; |
||
| 9 | |||
| 10 | protected $_message_folder; |
||
| 11 | protected $_queue_name; |
||
| 12 | protected $_message_folder_subfolder_count = Queue::DefaultMessageFolderSubfolderCount; |
||
| 13 | protected $_key_to_file = []; |
||
| 14 | protected $_is_inotify_enabled; |
||
| 15 | protected $_chunk_file_postfix = ''; |
||
| 16 | |||
| 17 | /** |
||
| 18 | * @var iMessage[] |
||
| 19 | */ |
||
| 20 | protected $_last_consumed_messages = []; |
||
| 21 | /** |
||
| 22 | * @var integer[] В keys список файлов, которые были прочитаны |
||
| 23 | */ |
||
| 24 | protected $_consumed_filenames = []; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @param SmallFilesQueueConstructionSettings|object $settings |
||
| 28 | * |
||
| 29 | * @throws QueueException |
||
| 30 | */ |
||
| 31 | 68 | function __construct($settings) { |
|
|
1 ignored issue
–
show
|
|||
| 32 | 68 | if (!isset($settings->message_folder)) { |
|
| 33 | 4 | throw new QueueException('message_folder has not been set'); |
|
| 34 | } |
||
| 35 | 64 | if (!isset($settings->name)) { |
|
| 36 | 4 | throw new QueueException('name has not been set'); |
|
| 37 | } |
||
| 38 | 60 | $this->_message_folder = $settings->message_folder; |
|
| 39 | 60 | $this->_queue_name = $settings->name; |
|
| 40 | 60 | if (isset($settings->message_folder_subfolder_count)) { |
|
| 41 | $this->_message_folder_subfolder_count = $settings->message_folder_subfolder_count; |
||
| 42 | } |
||
| 43 | 60 | if (isset($settings->is_inotify_enabled)) { |
|
| 44 | $this->_is_inotify_enabled = $settings->is_inotify_enabled; |
||
| 45 | } else { |
||
| 46 | 60 | $this->_is_inotify_enabled = function_exists('inotify_init'); |
|
| 47 | } |
||
| 48 | 60 | $this->_chunk_file_postfix = '_'.static::generate_rnd_postfix(); |
|
| 49 | 60 | } |
|
| 50 | |||
| 51 | /** |
||
| 52 | * @param boolean $mode |
||
| 53 | * |
||
| 54 | * @hint Ничего не делаем, у этого транспорта нет эксклюзивного режима |
||
| 55 | * @codeCoverageIgnore |
||
| 56 | */ |
||
| 57 | function set_exclusive_mode($mode) { } |
||
| 58 | |||
| 59 | /** |
||
| 60 | * @return string |
||
| 61 | */ |
||
| 62 | 692 | function get_queue_name() { |
|
| 65 | |||
| 66 | 620 | function save() { |
|
| 98 | |||
| 99 | /** |
||
| 100 | * @param double|integer $wait_time |
||
| 101 | * |
||
| 102 | * @return iMessage|object|null |
||
| 103 | * @throws QueueException |
||
| 104 | */ |
||
| 105 | 696 | function consume_next_message($wait_time = -1) { |
|
| 122 | |||
| 123 | 8 | function clear_consumed_keys() { |
|
| 128 | |||
| 129 | 736 | function __clone() { |
|
| 135 | |||
| 136 | /** |
||
| 137 | * @param double|integer $wait_time |
||
| 138 | * |
||
| 139 | * @return iMessage|object|null |
||
| 140 | */ |
||
| 141 | 696 | protected function consume_next_message_without_inotify($wait_time = -1) { |
|
| 158 | |||
| 159 | /** |
||
| 160 | * @param string $folder |
||
| 161 | * |
||
| 162 | * @return iMessage|object|null |
||
| 163 | */ |
||
| 164 | 680 | protected function consume_next_message_without_inotify_folder($folder) { |
|
| 181 | |||
| 182 | |||
| 183 | /** |
||
| 184 | * Забираем новые event'ы из файла. Файл должен быть уже существующим, читабельным |
||
| 185 | * |
||
| 186 | * Проверка на присутствие в индексе осуществляется в этом файле |
||
| 187 | * |
||
| 188 | * @param string $filename |
||
| 189 | * |
||
| 190 | * @return iMessage|object|null |
||
| 191 | */ |
||
| 192 | 680 | protected function consume_next_message_from_file($filename) { |
|
| 193 | 680 | if (isset($this->_consumed_filenames[$filename])) { |
|
| 194 | 660 | return null; |
|
| 195 | } |
||
| 196 | |||
| 197 | 680 | $fi = fopen($filename, 'r'); |
|
| 198 | 680 | $locked = flock($fi, LOCK_EX | LOCK_NB); |
|
| 199 | 680 | if (!$locked) { |
|
| 200 | 4 | fclose($fi); |
|
| 201 | |||
| 202 | 4 | return null; |
|
| 203 | } |
||
| 204 | |||
| 205 | 680 | $buf = file_get_contents($filename); |
|
| 206 | /** |
||
| 207 | * @var SmallFilesQueueSingleFile $file_data |
||
| 208 | */ |
||
| 209 | 680 | $file_data = @unserialize($buf); |
|
| 210 | 680 | if (!is_object($file_data)) { |
|
| 211 | // File does not contain Single Queue object |
||
| 212 | 3 | flock($fi, LOCK_UN); |
|
| 213 | 3 | fclose($fi); |
|
| 214 | |||
| 215 | 3 | return null; |
|
| 216 | } |
||
| 217 | 680 | if ($file_data->queue_name != $this->get_queue_name()) { |
|
| 218 | 8 | flock($fi, LOCK_UN); |
|
| 219 | 8 | fclose($fi); |
|
| 220 | |||
| 221 | 8 | return null; |
|
| 222 | } |
||
| 223 | 680 | if ($file_data->version != self::SINGLE_FILE_DB_VERSION) { |
|
| 224 | flock($fi, LOCK_UN); |
||
| 225 | fclose($fi); |
||
| 226 | |||
| 227 | return null; |
||
| 228 | } |
||
| 229 | |||
| 230 | 680 | $this->_last_consumed_messages = []; |
|
| 231 | 680 | foreach ($file_data->queue as $message) { |
|
| 232 | 680 | $key = self::get_real_key_for_message($message); |
|
| 233 | 680 | if (isset($this->_consumed_keys[$key])) { |
|
| 234 | 8 | continue; |
|
| 235 | } |
||
| 236 | |||
| 237 | 680 | $message->time_consumed = microtime(true); |
|
| 238 | 680 | $message->queue = $this; |
|
| 239 | 680 | $this->_key_to_file[$key] = $filename; |
|
| 240 | 680 | $this->_last_consumed_messages[] = $message; |
|
| 241 | 680 | $this->_consumed_keys[$key] = 1; |
|
| 242 | 170 | } |
|
| 243 | 680 | flock($fi, LOCK_UN); |
|
| 244 | 680 | fclose($fi); |
|
| 245 | 680 | $this->_consumed_filenames[$filename] = 1; |
|
| 246 | |||
| 247 | 680 | return !empty($this->_last_consumed_messages) ? array_shift($this->_last_consumed_messages) : null; |
|
| 248 | } |
||
| 249 | |||
| 250 | /** |
||
| 251 | * @param iMessage[]|object[] $messages |
||
| 252 | */ |
||
| 253 | 312 | protected function copy_key_to_file_from_messages(array $messages) { |
|
| 262 | |||
| 263 | /** |
||
| 264 | * @param iMessage[]|object[] $messages |
||
| 265 | * |
||
| 266 | * @return array[] |
||
| 267 | */ |
||
| 268 | 312 | protected function get_filenames_from_messages(array $messages) { |
|
| 288 | |||
| 289 | /** |
||
| 290 | * Удалить сообщения и сразу же записать это в БД |
||
| 291 | * |
||
| 292 | * @param iMessage[]|object[] $messages |
||
| 293 | * |
||
| 294 | * @return string[]|integer[] |
||
| 295 | * @throws QueueException |
||
| 296 | */ |
||
| 297 | 312 | function delete_messages(array $messages) { |
|
| 406 | |||
| 407 | /** |
||
| 408 | * Обновляем сообщение и сразу же сохраняем всё |
||
| 409 | * |
||
| 410 | * Эта функция не рейзит ошибку, если сообщение не найдено |
||
| 411 | * |
||
| 412 | * @param iMessage|object $message |
||
| 413 | * @param string|null $key форсированно задаём ключ сообщения |
||
| 414 | * |
||
| 415 | * @return boolean |
||
| 416 | * @throws QueueException |
||
| 417 | */ |
||
| 418 | 320 | function update_message($message, $key = null) { |
|
| 485 | |||
| 486 | /** |
||
| 487 | * Поддерживает ли очередь сортировку event'ов при вставке |
||
| 488 | * |
||
| 489 | * @return boolean |
||
| 490 | */ |
||
| 491 | 4 | static function is_support_sorted_events() { |
|
| 494 | |||
| 495 | /* |
||
| 496 | * @param double|integer $wait_time |
||
| 497 | * |
||
| 498 | * @return iMessage|object|null |
||
| 499 | * |
||
| 500 | * @throws QueueException |
||
| 501 | * @codeCoverageIgnore |
||
| 502 | / |
||
| 503 | protected function consume_next_message_with_inotify($wait_time = -1) { |
||
| 504 | $start = microtime(true); |
||
| 505 | // @todo написать |
||
| 506 | throw new QueueException('Не готово'); |
||
| 507 | } |
||
| 508 | */ |
||
| 509 | |||
| 510 | /* |
||
| 511 | * @codeCoverageIgnore |
||
| 512 | / |
||
| 513 | function test_inotify() { |
||
| 514 | // @todo этого тут быть не должно |
||
| 515 | $a = inotify_init(); |
||
| 516 | } |
||
| 517 | */ |
||
| 518 | |||
| 519 | /** |
||
| 520 | * @param SmallFilesQueueTransport $queue |
||
| 521 | * |
||
| 522 | * @return boolean |
||
| 523 | */ |
||
| 524 | 340 | function is_equal_to($queue) { |
|
| 535 | } |
||
| 536 | |||
| 537 | ?> |
Adding explicit visibility (
private,protected, orpublic) is generally recommend to communicate to other developers how, and from where this method is intended to be used.