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 | public static function db_query($query, $fetch = false, $skip_lock = false) { |
||
| 444 | |||
| 445 | /** |
||
| 446 | * Возвращает информацию о записи по её ID |
||
| 447 | * |
||
| 448 | * @param int $location_type |
||
| 449 | * @param int|array $record_id_unsafe |
||
| 450 | * <p>int - ID записи</p> |
||
| 451 | * <p>array - запись пользователя с установленным полем P_ID</p> |
||
| 452 | * @param bool $for_update @deprecated |
||
| 453 | * @param string $fields @deprecated список полей или '*'/'' для всех полей |
||
| 454 | * @param bool $skip_lock Указывает на то, что не нужно блокировать запись //TODO и не нужно сохранять в кэше |
||
| 455 | * |
||
| 456 | * @return array|false |
||
| 457 | * <p>false - Нет записи с указанным ID</p> |
||
| 458 | * <p>array - запись</p> |
||
| 459 | */ |
||
| 460 | public static function db_get_record_by_id($location_type, $record_id_unsafe, $for_update = false, $fields = '*', $skip_lock = false) { |
||
| 466 | |||
| 467 | public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) { |
||
| 529 | |||
| 530 | /** |
||
| 531 | * @param int $location_type |
||
| 532 | * @param int $record_id |
||
| 533 | * @param string $set - SQL SET structure |
||
| 534 | * |
||
| 535 | * @return array|bool|mysqli_result|null |
||
| 536 | */ |
||
| 537 | public static function db_upd_record_by_id($location_type, $record_id, $set) { |
||
| 561 | |||
| 562 | public static function db_upd_record_list($location_type, $condition, $set) { |
||
| 581 | |||
| 582 | /** |
||
| 583 | * @param int $location_type |
||
| 584 | * @param string $set |
||
| 585 | * |
||
| 586 | * @return array|bool|false|mysqli_result|null |
||
| 587 | */ |
||
| 588 | public static function db_ins_record($location_type, $set) { |
||
| 605 | |||
| 606 | public static function db_ins_field_set($location_type, $field_set, $serialize = false) { |
||
| 628 | |||
| 629 | public static function db_del_record_by_id($location_type, $safe_record_id) { |
||
| 646 | |||
| 647 | public static function db_del_record_list($location_type, $condition) { |
||
| 666 | |||
| 667 | |||
| 668 | |||
| 669 | // Работа с пользователями |
||
| 670 | /** |
||
| 671 | * Возвращает информацию о пользователе по его ID |
||
| 672 | * |
||
| 673 | * @param int|array $user_id_unsafe |
||
| 674 | * <p>int - ID пользователя</p> |
||
| 675 | * <p>array - запись пользователя с установленным полем ['id']</p> |
||
| 676 | * @param bool $for_update @deprecated |
||
| 677 | * @param string $fields @deprecated список полей или '*'/'' для всех полей |
||
| 678 | * @param null $player |
||
| 679 | * @param bool|null $player Признак выбора записи пользователь типа "игрок" |
||
| 680 | * <p>null - Можно выбрать запись любого типа</p> |
||
| 681 | * <p>true - Выбирается только запись типа "игрок"</p> |
||
| 682 | * <p>false - Выбирается только запись типа "альянс"</p> |
||
| 683 | * |
||
| 684 | * @return array|false |
||
| 685 | * <p>false - Нет записи с указанным ID и $player</p> |
||
| 686 | * <p>array - запись типа $user</p> |
||
| 687 | */ |
||
| 688 | public static function db_get_user_by_id($user_id_unsafe, $for_update = false, $fields = '*', $player = null) { |
||
| 700 | |||
| 701 | public static function db_get_user_by_username($username_unsafe, $for_update = false, $fields = '*', $player = null, $like = false) { |
||
| 702 | // TODO Проверить, кстати - а везде ли нужно выбирать юзеров или где-то все-таки ищутся Альянсы ? |
||
| 703 | if (!($username_unsafe = trim($username_unsafe))) { |
||
| 704 | return false; |
||
| 705 | } |
||
| 706 | |||
| 707 | $user = null; |
||
| 708 | if (is_array(static::$data[LOC_USER])) { |
||
| 709 | foreach (static::$data[LOC_USER] as $user_id => $user_data) { |
||
| 710 | if (is_array($user_data) && isset($user_data['username'])) { |
||
| 711 | // проверяем поле |
||
| 712 | // TODO Возможно есть смысл всегда искать по strtolower - но может игрок захочет переименоваться с другим регистром? Проверить! |
||
| 713 | if ((!$like && $user_data['username'] == $username_unsafe) || ($like && strtolower($user_data['username']) == strtolower($username_unsafe))) { |
||
| 714 | // $user_as_ally = intval($user_data['user_as_ally']); |
||
| 715 | $user_as_ally = idval($user_data['user_as_ally']); |
||
| 716 | if ($player === null || ($player === true && !$user_as_ally) || ($player === false && $user_as_ally)) { |
||
| 717 | $user = $user_data; |
||
| 718 | break; |
||
| 719 | } |
||
| 720 | } |
||
| 721 | } |
||
| 722 | } |
||
| 723 | } |
||
| 724 | |||
| 725 | if ($user === null) { |
||
| 726 | // Вытаскиваем запись |
||
| 727 | $username_safe = db_escape($like ? strtolower($username_unsafe) : $username_unsafe); // тут на самом деле strtolower() лишняя, но пусть будет |
||
| 728 | |||
| 729 | // TODO переписать |
||
| 730 | $user = static::db_query( |
||
| 731 | "SELECT * FROM {{users}} WHERE `username` " . ($like ? 'LIKE' : '=') . " '{$username_safe}'" |
||
| 732 | , true); |
||
| 733 | static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы |
||
| 734 | } |
||
| 735 | |||
| 736 | return $user; |
||
| 737 | } |
||
| 738 | |||
| 739 | // UNUSED |
||
| 740 | // public static function db_get_user_by_email($email_unsafe, $use_both = false, $for_update = false, $fields = '*') { |
||
| 741 | // if (!($email_unsafe = strtolower(trim($email_unsafe)))) { |
||
| 742 | // return false; |
||
| 743 | // } |
||
| 744 | // |
||
| 745 | // $user = null; |
||
| 746 | // // TODO переделать на индексы |
||
| 747 | // if (is_array(static::$data[LOC_USER])) { |
||
| 748 | // foreach (static::$data[LOC_USER] as $user_id => $user_data) { |
||
| 749 | // if (is_array($user_data) && isset($user_data['email_2'])) { |
||
| 750 | // // проверяем поле |
||
| 751 | // if (strtolower($user_data['email_2']) == $email_unsafe || ($use_both && strtolower($user_data['email']) == $email_unsafe)) { |
||
| 752 | // $user = $user_data; |
||
| 753 | // break; |
||
| 754 | // } |
||
| 755 | // } |
||
| 756 | // } |
||
| 757 | // } |
||
| 758 | // |
||
| 759 | // if ($user === null) { |
||
| 760 | // // Вытаскиваем запись |
||
| 761 | // $email_safe = db_escape($email_unsafe); |
||
| 762 | // $user = static::db_query( |
||
| 763 | // "SELECT * FROM {{users}} WHERE LOWER(`email_2`) = '{$email_safe}'" . |
||
| 764 | // ($use_both ? " OR LOWER(`email`) = '{$email_safe}'" : '') |
||
| 765 | // , true); |
||
| 766 | // |
||
| 767 | // static::cache_set(LOC_USER, $user); // В кэш-юзер так же заполнять индексы |
||
| 768 | // } |
||
| 769 | // |
||
| 770 | // return $user; |
||
| 771 | // } |
||
| 772 | |||
| 773 | public static function db_get_user_by_where($where_safe, $for_update = false, $fields = '*') { |
||
| 786 | |||
| 787 | |||
| 788 | View Code Duplication | public static function db_unit_time_restrictions($date = SN_TIME_NOW) { |
|
| 795 | |||
| 796 | public static function db_get_unit_by_id($unit_id, $for_update = false, $fields = '*') { |
||
| 805 | |||
| 806 | /** |
||
| 807 | * @param int $user_id |
||
| 808 | * @param $location_type |
||
| 809 | * @param $location_id |
||
| 810 | * |
||
| 811 | * @return array|bool |
||
| 812 | */ |
||
| 813 | public static function db_get_unit_list_by_location($user_id = 0, $location_type, $location_id) { |
||
| 837 | |||
| 838 | public static function db_get_unit_by_location($user_id = 0, $location_type, $location_id, $unit_snid = 0, $for_update = false, $fields = '*') { |
||
| 843 | |||
| 844 | |||
| 845 | /* |
||
| 846 | * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы! |
||
| 847 | * |
||
| 848 | * $que_type |
||
| 849 | * !$que_type - все очереди |
||
| 850 | * QUE_XXXXXX - конкретная очередь по планете |
||
| 851 | * $user_id - ID пользователя |
||
| 852 | * $planet_id |
||
| 853 | * $que_type == QUE_RESEARCH - игнорируется |
||
| 854 | * null - обработка очередей планет не производится |
||
| 855 | * false/0 - обрабатываются очереди всех планет по $user_id |
||
| 856 | * (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов |
||
| 857 | * иначе - $que_type для указанной планеты |
||
| 858 | * $for_update - true == нужно блокировать записи |
||
| 859 | * |
||
| 860 | * TODO Работа при !$user_id |
||
| 861 | * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить подмассивы 'que', 'planets', 'players' |
||
| 862 | * |
||
| 863 | */ |
||
| 864 | public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) { |
||
| 891 | |||
| 892 | |||
| 893 | View Code Duplication | public static function db_changeset_prepare_unit($unit_id, $unit_value, $user, $planet_id = null) { |
|
| 955 | |||
| 956 | |||
| 957 | public function db_changeset_delay($table_name, $table_data) { |
||
| 963 | |||
| 964 | public function db_changeset_revert() { |
||
| 970 | |||
| 971 | public function db_changeset_condition_compile(&$conditions, &$table_name = '') { |
||
| 1053 | |||
| 1054 | public static function db_changeset_apply($db_changeset, $flush_delayed = false) { |
||
| 1095 | |||
| 1096 | |||
| 1097 | |||
| 1098 | |||
| 1099 | |||
| 1100 | |||
| 1101 | |||
| 1102 | |||
| 1103 | |||
| 1104 | |||
| 1105 | |||
| 1106 | |||
| 1107 | |||
| 1108 | |||
| 1109 | |||
| 1110 | |||
| 1111 | |||
| 1112 | |||
| 1113 | |||
| 1114 | |||
| 1115 | |||
| 1116 | |||
| 1117 | |||
| 1118 | |||
| 1119 | |||
| 1120 | |||
| 1121 | |||
| 1122 | |||
| 1123 | |||
| 1124 | |||
| 1125 | |||
| 1126 | |||
| 1127 | |||
| 1128 | |||
| 1129 | |||
| 1130 | // que_process не всегда должна работать в режиме прямой работы с БД !! Она может работать и в режиме эмуляции |
||
| 1131 | // !!!!!!!! После que_get брать не [0] элемент, а first() - тогда можно в индекс элемента засовывать que_id из таблицы |
||
| 1132 | |||
| 1133 | |||
| 1134 | // Это для поиска по кэшу |
||
| 1135 | protected static function db_get_record_by_field($location_type) { |
||
| 1137 | |||
| 1138 | // Для модулей - регистрация юнитов |
||
| 1139 | public static function unit_register() { |
||
| 1142 | |||
| 1143 | |||
| 1144 | public static function init_0_prepare() { |
||
| 1159 | |||
| 1160 | public static function init_3_load_config_file() { |
||
| 1169 | |||
| 1170 | public static function init_global_objects() { |
||
| 1192 | |||
| 1193 | public static function init_debug_state() { |
||
| 1216 | |||
| 1217 | } |
||
| 1218 |
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: