Рефакторинг небольшого скрипта 1С‑Битрикс: от простыни к классу и исключениям
Зачем трогать рабочий скрипт
Типичный сценарий: под задачу быстро набросали отдельный PHP‑файл в каталоге /bitrix/php_interface/ или рядом с компонентом. Он уже обслуживает запрос, но разросся до сотни с лишним строк без функций и без класса — логика скачет сверху вниз, временные массивы для выборки и фильтра объявлены в одном месте, а фактически нужны только в середине и внизу. Такой код трудно сопровождать: правка в одной ветке легко ломает другое место, потому что всё видит одни и те же имена.
Ниже — не «большой рефакторинг на неделю», а практичный набор приёмов: один входной метод вроде run(), мелкие шаги, исключения как нормальный способ сказать «стоп, ответ клиенту уже известен», и локальные переменные внутри методов вместо полотна на весь файл.
До и после в двух словах
| Было | Стало |
|---|---|
| Одна длинная процедура, сложно проследить поток | Короткий сценарий из вызовов методов, каждый шаг читается отдельно |
Ошибки оформляются через return и дублирование выхода | Исключения с понятным сообщением; общий перехват в одном месте превращает их в JSON или редирект |
| Переменные «живут» на всей высоте файла | Временные структуры создаются внутри метода и не засоряют глобальное чтение скрипта |
Модульность: один run() и шаги
Вместо того чтобы читать файл от начала до конца, вы описываете сценарий из пяти–семи шагов: проверить сессию и права, разобрать входные данные, загрузить сущности, выполнить действие, собрать ответ. На каждом шаге при нарушении условий выбрасывается исключение — это короче, чем в каждой ветке вручную заполнять объект ответа и делать return. Внешний перехватчик знает, как превратить исключение в HTTP‑код и тело JSON.
Исключения вместо раннего выхода
Сравните два стиля для одной и той же проверки авторизации. В процедурном варианте вы каждый раз помните про корректное завершение ответа. В объектном — нарушение условия выражено одной строкой, а формат ошибки концентрируется в обработчике.
<?php
if (!$USER->IsAuthorized()) {
$payload->setError('Нужна авторизация');
return;
}
<?php
if (!$this->user->IsAuthorized()) {
throw new \RuntimeException('Нужна авторизация', 401);
}
Коды и классы исключений подберите под свой каркас: главное — не смешивать бизнес‑ошибки и фатальные сбои в одну кучу без типизации, если дальше вы хотите по-разному логировать и отдавать клиенту.
Область видимости и «забытые» временные переменные
Классический антипаттерн — объявить $fieldSelection и $elementFilter в начале скрипта, а использовать их через сотню строк: между объявлением и чтением оказывается половина ветвлений, и непонятно, не перезаписали ли массив по дороге. Вариант с unset($fieldSelection, $elementFilter, $dbResult) в конце блока лечит симптом, но не причину.
Если вынести выборку в метод fetchElementsForRequest(RequestData $input): array, все временные структуры живут внутри него и исчезают вместе с завершением вызова — меньше риска случайно переиспользовать имя и проще смотреть diff в Git.
<?php
private function fetchElementsForRequest(RequestData $input): array
{
$fieldSelection = ['ID', 'NAME', 'XML_ID'];
$elementFilter = ['IBLOCK_ID' => $input->getIblockId(), 'ACTIVE' => 'Y'];
// ... CIBlockElement::GetList или D7-таблица
return $rows;
}
Комментарии и тексты ошибок
Мелочь, которая портит жизнь при ревью: опечатки в сообщениях пользователю и в комментариях («элемид», «иммет»). После нарезки на методы проще пройтись по строкам и выровнять формулировки — чистый текст дешевле сопровождать, чем объяснять новому разработчику, что «элемид» — это всё же элемент.
Кратко
- Разбейте сценарий на короткие методы и один явный вход (
runили фасад). - Используйте исключения для нарушенных предусловий и централизуйте ответ клиенту.
- Держите временные массивы и результаты выборок внутри узких методов.
- Подчистите пользовательские тексты и комментарии — это часть качества кода.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии