Как избежать бесконечной рекурсии при использовании директивы &Вместо в расширении конфигурации 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При доработке типовых конфигураций с помощью механизма расширений часто возникает задача скорректировать работу существующей процедуры или функции общего модуля. Для перехвата управления разработчики используют аннотацию &Вместо. Однако при попытке вызвать исходную реализацию метода стандартным обращением к общему модулю программа уходит в бесконечную рекурсию и аварийно завершает работу.

Разберем причины возникновения этой ошибки и подробно рассмотрим правильный способ вызова исходного метода через платформенный механизм ПродолжитьВызов().

Почему возникает рекурсия при прямом вызове метода модуля

Проанализируем типичную ошибку в коде расширения. Предположим, в общем модуле Модуль объявлена экспортная функция НужнаяМнеФункция(Параметр). Разработчик подключает расширение и объявляет перехватчик:


&Вместо("НужнаяМнеФункция")
Функция Расш_НужнаяМнеФункция(Знач Параметр)
    Результат = Модуль.НужнаяМнеФункция(Параметр); // Здесь возникает рекурсия
    
    // Модификация результата
    Результат = Результат + 10;
    Возврат Результат;
КонецФункции

Выясним причину такого поведения. Когда платформа 1С компилирует вызовы методов конфигурации с подключенными расширениями, аннотация &Вместо полностью подменяет точку входа исходного метода. Любое обращение вида Модуль.НужнаяМнеФункция(...) из любого места конфигурации или самого расширения снова направляется в метод-перехватчик Расш_НужнаяМнеФункция. В результате функция непрерывно вызывает саму себя, пока стек вызовов не переполнится.

Штатное решение: использование метода ПродолжитьВызов()

Для корректной передачи управления оригинальному коду конфигурации платформа 1С предоставляет специальный метод ПродолжитьВызов(). Этот метод сообщает платформе, что необходимо выполнить исходное тело перехваченного метода (или передать управление следующему по приоритету расширению, если их несколько).

Посмотрим на исправленный и правильный вариант функции расширения:


&Вместо("НужнаяМнеФункция")
Функция Расш_НужнаяМнеФункция(Знач Параметр)
    // Вызываем оригинальный метод конфигурации через ПродолжитьВызов
    Результат = ПродолжитьВызов(Параметр);
    
    // Выполняем постобработку полученного результата
    Если ЗначениеЗаполнено(Результат) Тогда
        Результат = МодифицироватьЗначение(Результат);
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Особенности и правила работы с ПродолжитьВызов()

Рассмотрим ключевые нюансы, которые необходимо соблюдать при написании перехватчиков с аннотацией &Вместо:

  1. Передача параметров: В метод ПродолжитьВызов() необходимо передавать параметры точно в таком количестве и порядке, в каком они объявлены в сигнатуре исходного метода. При необходимости значения параметров перед передачей можно изменить.
  2. Получение результата для функций: Если переопределяется функция, результат обязательно возвращается через оператор присваивания: Результат = ПродолжитьВызов(...), после чего возвращается оператором Возврат.
  3. Использование в процедурах: Для процедур оператор вызова выглядит аналогично, но без присвоения значения: ПродолжитьВызов(Параметр1, Параметр2);.
  4. Цепочка расширений: Если один и тот же метод переопределен сразу в нескольких подключенных расширениях с разными приоритетами, вызов ПродолжитьВызов() последовательно вызовет метод следующего расширения и только в самом конце — базовый метод конфигурации.
  5. Полное замещение логики: Если исходный код метода выполнять вообще не требуется, метод ПродолжитьВызов() просто не вызывается в теле функции или процедуры расширения.

Ограничения платформы при перехвате методов

Разберем технические требования платформы 1С к переопределяемым методам:

  1. Область видимости: Перехватывать можно исключительно экспортные методы общих модулей, модулей менеджеров, модулей объектов и форм. Неэкспортные (внутренние) методы расширить директивами перехвата нельзя.
  2. Сигнатура метода: Список формальных параметров, их количество и модификаторы передачи (например, Знач) в методе расширения должны строго повторять сигнатуру базового метода.
  3. Директивы компиляции: Директива компиляции перехватчика (например, &НаСервере, &НаКлиенте или &НаСервереБезКонтекста) должна полностью совпадать с директивой исходного метода.

Таким образом, для безопасной модификации возвращаемого значения функций типовых модулей всегда используйте сочетание директивы &Вместо и вызова ПродолжитьВызов().

← На главную