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 classSupernova 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 classSupernova, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
3 | class classSupernova { |
||
4 | /** |
||
5 | * ex $sn_mvc |
||
6 | * |
||
7 | * @var array |
||
8 | */ |
||
9 | public static $sn_mvc = array(); |
||
10 | |||
11 | /** |
||
12 | * ex $functions |
||
13 | * |
||
14 | * @var array |
||
15 | */ |
||
16 | public static $functions = array(); |
||
17 | |||
18 | /** |
||
19 | * @var array[] $design |
||
20 | */ |
||
21 | public $design = array( |
||
22 | 'bbcodes' => array(), |
||
23 | 'smiles' => array(), |
||
24 | ); |
||
25 | |||
26 | /** |
||
27 | * Основная БД для доступа к данным |
||
28 | * |
||
29 | * @var db_mysql $db |
||
30 | */ |
||
31 | public static $db; |
||
32 | public static $db_name = ''; |
||
33 | |||
34 | /** |
||
35 | * Настройки из файла конфигурации |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | public static $cache_prefix = ''; |
||
40 | |||
41 | public static $sn_secret_word = ''; |
||
42 | |||
43 | /** |
||
44 | * Конфигурация игры |
||
45 | * |
||
46 | * @var classConfig $config |
||
47 | */ |
||
48 | public static $config; |
||
49 | |||
50 | |||
51 | /** |
||
52 | * Кэш игры |
||
53 | * |
||
54 | * @var classCache $cache |
||
55 | */ |
||
56 | public static $cache; |
||
57 | |||
58 | |||
59 | /** |
||
60 | * @var core_auth $auth |
||
61 | */ |
||
62 | public static $auth = null; |
||
63 | |||
64 | |||
65 | public static $db_in_transaction = false; |
||
66 | public static $db_records_locked = false; |
||
67 | public static $transaction_id = 0; |
||
68 | public static $user = array(); |
||
69 | /** |
||
70 | * @var userOptions |
||
71 | */ |
||
72 | public static $user_options; |
||
73 | |||
74 | /** |
||
75 | * @var debug $debug |
||
76 | */ |
||
77 | public static $debug = null; |
||
78 | |||
79 | public $options = array(); |
||
80 | |||
81 | public static $data = array(); // Кэш данных - юзера, планеты, юниты, очередь, альянсы итд |
||
82 | public static $locks = array(); // Информация о блокировках |
||
83 | public static $queries = array(); // Кэш запросов |
||
84 | |||
85 | // Массив $locator - хранит отношения между записями для быстрого доступа по тип_записи:тип_локации:ид_локации:внутренний_ид_записи=>информация |
||
86 | // Для LOC_UNIT внутренний ИД - это SNID, а информация - это ссылка на запись `unit` |
||
87 | // Для LOC_QUE внутренний ИД - это тип очереди, а информация - массив ссылок на `que` |
||
88 | public static $locator = array(); // Кэширует соответствия между расположением объектов - в частности юнитов и очередей |
||
89 | |||
90 | public static $delayed_changset = array(); // Накопительный массив изменений |
||
91 | |||
92 | // Кэш индексов - ключ MD5-строка от суммы ключевых строк через | - менять | на что-то другое перед поиском и назад - после поиска |
||
93 | // Так же в индексах могут быть двойные вхождения - например, названия планет да и вообще |
||
94 | // Придумать спецсимвол для NULL |
||
95 | |||
96 | /* |
||
97 | TODO Кэш: |
||
98 | 1. Всегда дешевле использовать процессор, чем локальную память |
||
99 | 2. Всегда дешевле использовать локальную память, чем общую память всех процессов |
||
100 | 3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД |
||
101 | |||
102 | Кэш - многоуровневый: локальная память-общая память-БД |
||
103 | БД может быть сверхкэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД |
||
104 | Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xcache и используется общая память |
||
105 | */ |
||
106 | |||
107 | // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице |
||
108 | public static $location_info = array( |
||
109 | LOC_USER => array( |
||
110 | P_TABLE_NAME => 'users', |
||
111 | P_ID => 'id', |
||
112 | P_OWNER_INFO => array(), |
||
113 | ), |
||
114 | |||
115 | LOC_PLANET => array( |
||
116 | P_TABLE_NAME => 'planets', |
||
117 | P_ID => 'id', |
||
118 | P_OWNER_INFO => array( |
||
119 | LOC_USER => array( |
||
120 | P_LOCATION => LOC_USER, |
||
121 | P_OWNER_FIELD => 'id_owner', |
||
122 | ), |
||
123 | ), |
||
124 | ), |
||
125 | |||
126 | LOC_UNIT => array( |
||
127 | P_TABLE_NAME => 'unit', |
||
128 | P_ID => 'unit_id', |
||
129 | P_OWNER_INFO => array( |
||
130 | LOC_USER => array( |
||
131 | P_LOCATION => LOC_USER, |
||
132 | P_OWNER_FIELD => 'unit_player_id', |
||
133 | ), |
||
134 | ), |
||
135 | ), |
||
136 | |||
137 | LOC_QUE => array( |
||
138 | P_TABLE_NAME => 'que', |
||
139 | P_ID => 'que_id', |
||
140 | P_OWNER_INFO => array( |
||
141 | array( |
||
142 | P_LOCATION => LOC_USER, |
||
143 | P_OWNER_FIELD => 'que_player_id', |
||
144 | ), |
||
145 | |||
146 | array( |
||
147 | P_LOCATION => LOC_PLANET, |
||
148 | P_OWNER_FIELD => 'que_planet_id_origin', |
||
149 | ), |
||
150 | |||
151 | array( |
||
152 | P_LOCATION => LOC_PLANET, |
||
153 | P_OWNER_FIELD => 'que_planet_id', |
||
154 | ), |
||
155 | ), |
||
156 | ), |
||
157 | |||
158 | LOC_FLEET => array( |
||
159 | P_TABLE_NAME => 'fleets', |
||
160 | P_ID => 'fleet_id', |
||
161 | P_OWNER_INFO => array( |
||
162 | array( |
||
163 | P_LOCATION => LOC_USER, |
||
164 | P_OWNER_FIELD => 'fleet_owner', |
||
165 | ), |
||
166 | |||
167 | array( |
||
168 | P_LOCATION => LOC_USER, |
||
169 | P_OWNER_FIELD => 'fleet_target_owner', |
||
170 | ), |
||
171 | |||
172 | array( |
||
173 | P_LOCATION => LOC_PLANET, |
||
174 | P_OWNER_FIELD => 'fleet_start_planet_id', |
||
175 | ), |
||
176 | |||
177 | array( |
||
178 | P_LOCATION => LOC_PLANET, |
||
179 | P_OWNER_FIELD => 'fleet_end_planet_id', |
||
180 | ), |
||
181 | ), |
||
182 | ), |
||
183 | ); |
||
184 | |||
185 | /** |
||
186 | * @param $db db_mysql |
||
187 | */ |
||
188 | public static function init_main_db($db) { |
||
192 | |||
193 | |||
194 | public static function log_file($message, $spaces = 0) { |
||
199 | |||
200 | public static function debug_set_handler($debug) { |
||
203 | |||
204 | // Перепаковывает массив на заданную глубину, убирая поля с null |
||
205 | public static function array_repack(&$array, $level = 0) { |
||
222 | |||
223 | |||
224 | // TODO Вынести в отдельный объект |
||
225 | public static function cache_repack($location_type, $record_id = 0) { |
||
235 | |||
236 | public static function cache_clear($location_type, $hard = true) { |
||
245 | |||
246 | public static function cache_clear_all($hard = true) { |
||
254 | |||
255 | public static function cache_get($location_type, $record_id) { |
||
258 | |||
259 | public static function cache_isset($location_type, $record_id) { |
||
262 | |||
263 | /* Кэшируем запись в соответствующий кэш |
||
264 | |||
265 | Писать в кэш: |
||
266 | 1. Если записи не существует в кэше |
||
267 | 2. Если стоит $force_overwrite |
||
268 | 3. Если во время транзакции существующая запись не заблокирована |
||
269 | |||
270 | Блокировать запись: |
||
271 | 1. Если идет транзакция и запись не заблокирована |
||
272 | 2. Если не стоит скип-лок |
||
273 | */ |
||
274 | public static function cache_set($location_type, $record, $force_overwrite = false, $skip_lock = false) { |
||
295 | |||
296 | public static function cache_unset($cache_id, $safe_record_id) { |
||
305 | |||
306 | public static function cache_lock_get($location_type, $record_id) { |
||
309 | |||
310 | public static function cache_lock_set($location_type, $record_id) { |
||
313 | |||
314 | public static function cache_lock_unset($location_type, $record_id) { |
||
321 | |||
322 | public static function cache_lock_unset_all() { |
||
329 | |||
330 | |||
331 | |||
332 | |||
333 | |||
334 | // TODO Вынести в отдельный объект |
||
335 | /** |
||
336 | * Эта функция проверяет статус транзакции |
||
337 | * |
||
338 | * Это - низкоуровневая функция. В нормальном состоянии движка её сообщения никогда не будут видны |
||
339 | * |
||
340 | * @param null|true|false $status Должна ли быть запущена транзакция в момент проверки |
||
341 | * <p>null - транзакция НЕ должна быть запущена</p> |
||
342 | * <p>true - транзакция должна быть запущена - для совместимости с $for_update</p> |
||
343 | * <p>false - всё равно - для совместимости с $for_update</p> |
||
344 | * |
||
345 | * @return bool Текущий статус транзакции |
||
346 | */ |
||
347 | public static function db_transaction_check($status = null) { |
||
366 | |||
367 | public static function db_transaction_start($level = '') { |
||
386 | |||
387 | public static function db_transaction_commit() { |
||
397 | |||
398 | public static function db_transaction_rollback() { |
||
408 | |||
409 | protected static function db_transaction_clear() { |
||
419 | |||
420 | /** |
||
421 | * Блокирует указанные таблицу/список таблиц |
||
422 | * |
||
423 | * @param string|array $tables Таблица/список таблиц для блокировки. Названия таблиц - без префиксов |
||
424 | * <p>string - название таблицы для блокировки</p> |
||
425 | * <p>array - массив, где ключ - имя таблицы, а значение - условия блокировки элементов</p> |
||
426 | */ |
||
427 | public static function db_lock_tables($tables) { |
||
433 | |||
434 | /** |
||
435 | * @param DbSqlStatement $statement |
||
436 | * @param bool $skip_lock |
||
437 | * |
||
438 | * @return array|null |
||
439 | */ |
||
440 | public static function dbFetchOne($statement, $skip_lock = false) { |
||
448 | |||
449 | /** |
||
450 | * @param $query |
||
451 | * @param bool $fetch |
||
452 | * @param bool $skip_lock |
||
453 | * |
||
454 | * @return array|bool|mysqli_result|null |
||
455 | */ |
||
456 | public static function db_query($query, $fetch = false, $skip_lock = false) { |
||
466 | |||
467 | /** |
||
468 | * Возвращает информацию о записи по её ID |
||
469 | * |
||
470 | * @param int $location_type |
||
471 | * @param int|array $record_id_unsafe |
||
472 | * <p>int - ID записи</p> |
||
473 | * <p>array - запись пользователя с установленным полем P_ID</p> |
||
474 | * @param bool $for_update @deprecated |
||
475 | * @param string $fields @deprecated список полей или '*'/'' для всех полей |
||
476 | * @param bool $skip_lock Указывает на то, что не нужно блокировать запись //TODO и не нужно сохранять в кэше |
||
477 | * |
||
478 | * @return array|false |
||
479 | * <p>false - Нет записи с указанным ID</p> |
||
480 | * <p>array - запись</p> |
||
481 | */ |
||
482 | public static function db_get_record_by_id($location_type, $record_id_unsafe, $for_update = false, $fields = '*', $skip_lock = false) { |
||
488 | |||
489 | public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) { |
||
551 | |||
552 | /** |
||
553 | * @param int $location_type |
||
554 | * @param int $record_id |
||
555 | * @param string $set - SQL SET structure |
||
556 | * |
||
557 | * @return array|bool|mysqli_result|null |
||
558 | */ |
||
559 | public static function db_upd_record_by_id($location_type, $record_id, $set) { |
||
583 | |||
584 | public static function db_upd_record_list($location_type, $condition, $set) { |
||
603 | |||
604 | /** |
||
605 | * @param int $location_type |
||
606 | * @param string $set |
||
607 | * |
||
608 | * @return array|bool|false|mysqli_result|null |
||
609 | */ |
||
610 | public static function db_ins_record($location_type, $set) { |
||
627 | |||
628 | public static function db_ins_field_set($location_type, $field_set, $serialize = false) { |
||
650 | |||
651 | public static function db_del_record_by_id($location_type, $safe_record_id) { |
||
668 | |||
669 | public static function db_del_record_list($location_type, $condition) { |
||
688 | |||
689 | |||
690 | |||
691 | // Работа с пользователями |
||
692 | /** |
||
693 | * Возвращает информацию о пользователе по его ID |
||
694 | * |
||
695 | * @param int|array $user_id_unsafe |
||
696 | * <p>int - ID пользователя</p> |
||
697 | * <p>array - запись пользователя с установленным полем ['id']</p> |
||
698 | * @param bool $for_update @deprecated |
||
699 | * @param string $fields @deprecated список полей или '*'/'' для всех полей |
||
700 | * @param null $player |
||
701 | * @param bool|null $player Признак выбора записи пользователь типа "игрок" |
||
702 | * <p>null - Можно выбрать запись любого типа</p> |
||
703 | * <p>true - Выбирается только запись типа "игрок"</p> |
||
704 | * <p>false - Выбирается только запись типа "альянс"</p> |
||
705 | * |
||
706 | * @return array|false |
||
707 | * <p>false - Нет записи с указанным ID и $player</p> |
||
708 | * <p>array - запись типа $user</p> |
||
709 | */ |
||
710 | public static function db_get_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) { |
||
722 | |||
723 | public static function db_get_user_by_username($username_unsafe, $for_update = false, $fields = '*', $player = null, $like = false) { |
||
765 | |||
766 | // UNUSED |
||
767 | // public static function db_get_user_by_email($email_unsafe, $use_both = false, $for_update = false, $fields = '*') { |
||
768 | // if (!($email_unsafe = strtolower(trim($email_unsafe)))) { |
||
769 | // return false; |
||
770 | // } |
||
771 | // |
||
772 | // $user = null; |
||
773 | // // TODO переделать на индексы |
||
774 | // if (is_array(static::$data[LOC_USER])) { |
||
775 | // foreach (static::$data[LOC_USER] as $user_id => $user_data) { |
||
776 | // if (is_array($user_data) && isset($user_data['email_2'])) { |
||
777 | // // проверяем поле |
||
778 | // if (strtolower($user_data['email_2']) == $email_unsafe || ($use_both && strtolower($user_data['email']) == $email_unsafe)) { |
||
779 | // $user = $user_data; |
||
780 | // break; |
||
781 | // } |
||
782 | // } |
||
783 | // } |
||
784 | // } |
||
785 | // |
||
786 | // if ($user === null) { |
||
787 | // // Вытаскиваем запись |
||
788 | // $email_safe = db_escape($email_unsafe); |
||
789 | // $user = static::db_query( |
||
790 | // "SELECT * FROM {{users}} WHERE LOWER(`email_2`) = '{$email_safe}'" . |
||
791 | // ($use_both ? " OR LOWER(`email`) = '{$email_safe}'" : '') |
||
792 | // , true); |
||
793 | // |
||
794 | // static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы |
||
795 | // } |
||
796 | // |
||
797 | // return $user; |
||
798 | // } |
||
799 | |||
800 | public static function db_get_user_by_where($where_safe, $for_update = false, $fields = '*') { |
||
813 | |||
814 | |||
815 | View Code Duplication | public static function db_unit_time_restrictions($date = SN_TIME_NOW) { |
|
822 | |||
823 | public static function db_get_unit_by_id($unit_id, $for_update = false, $fields = '*') { |
||
832 | |||
833 | /** |
||
834 | * @param int $user_id |
||
835 | * @param $location_type |
||
836 | * @param $location_id |
||
837 | * |
||
838 | * @return array|bool |
||
839 | */ |
||
840 | public static function db_get_unit_list_by_location($user_id = 0, $location_type, $location_id) { |
||
864 | |||
865 | public static function db_get_unit_by_location($user_id = 0, $location_type, $location_id, $unit_snid = 0, $for_update = false, $fields = '*') { |
||
870 | |||
871 | |||
872 | /* |
||
873 | * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы! |
||
874 | * |
||
875 | * $que_type |
||
876 | * !$que_type - все очереди |
||
877 | * QUE_XXXXXX - конкретная очередь по планете |
||
878 | * $user_id - ID пользователя |
||
879 | * $planet_id |
||
880 | * $que_type == QUE_RESEARCH - игнорируется |
||
881 | * null - обработка очередей планет не производится |
||
882 | * false/0 - обрабатываются очереди всех планет по $user_id |
||
883 | * (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов |
||
884 | * иначе - $que_type для указанной планеты |
||
885 | * $for_update - true == нужно блокировать записи |
||
886 | * |
||
887 | * TODO Работа при !$user_id |
||
888 | * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить подмассивы 'que', 'planets', 'players' |
||
889 | * |
||
890 | */ |
||
891 | public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) { |
||
918 | |||
919 | |||
920 | View Code Duplication | public static function db_changeset_prepare_unit($unit_id, $unit_value, $user, $planet_id = null) { |
|
982 | |||
983 | |||
984 | public function db_changeset_delay($table_name, $table_data) { |
||
990 | |||
991 | public function db_changeset_revert() { |
||
997 | |||
998 | public function db_changeset_condition_compile(&$conditions, &$table_name = '') { |
||
1080 | |||
1081 | public static function db_changeset_apply($db_changeset, $flush_delayed = false) { |
||
1122 | |||
1123 | |||
1124 | |||
1125 | |||
1126 | |||
1127 | |||
1128 | |||
1129 | |||
1130 | |||
1131 | |||
1132 | |||
1133 | |||
1134 | |||
1135 | |||
1136 | |||
1137 | |||
1138 | |||
1139 | |||
1140 | |||
1141 | |||
1142 | |||
1143 | |||
1144 | |||
1145 | |||
1146 | |||
1147 | |||
1148 | |||
1149 | |||
1150 | |||
1151 | |||
1152 | |||
1153 | |||
1154 | |||
1155 | |||
1156 | |||
1157 | // que_process не всегда должна работать в режиме прямой работы с БД !! Она может работать и в режиме эмуляции |
||
1158 | // !!!!!!!! После que_get брать не [0] элемент, а first() - тогда можно в индекс элемента засовывать que_id из таблицы |
||
1159 | |||
1160 | |||
1161 | // Это для поиска по кэшу |
||
1162 | protected static function db_get_record_by_field($location_type) { |
||
1164 | |||
1165 | // Для модулей - регистрация юнитов |
||
1166 | public static function unit_register() { |
||
1169 | |||
1170 | |||
1171 | public static function init_0_prepare() { |
||
1186 | |||
1187 | public static function init_3_load_config_file() { |
||
1196 | |||
1197 | public static function init_global_objects() { |
||
1219 | |||
1220 | public static function init_debug_state() { |
||
1243 | |||
1244 | } |
||
1245 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: