При разработке расширений конфигурации разработчики 1С нередко сталкиваются с ситуацией: при попытке перехватить метод общего модуля или модуля объекта в контекстном меню доступны только варианты «Вместо» и «Вместо с контролем», в то время как привычные «Вызвать перед» и «Вызвать после» неактивны или отсутствуют вовсе. Разберем причины такого поведения платформы и рассмотрим правильные способы решения этой задачи.
Выясним причину такого поведения. Платформа «1С:Предприятие» строго разграничивает применение директив перехвата для процедур и функций:
&Перед, затем исходную процедуру конфигурации, а после нее — методы с директивой &После из одного или нескольких расширений.Возврат. Если бы платформа допускала применение &Перед и &После для функций, возникла бы архитектурная неоднозначность: какое именно значение считать итоговым результатом функции, если каждое расширение попытается его изменить, и в каком порядке эти значения должны перезаписываться?Именно поэтому для любых функций перехват через аннотации &Перед и &После на уровне платформы принципиально запрещен. Доступны только методы полной замены: &Вместо и &ИзменениеИКонтроль.
Проанализируем практическое решение. Если нам требуется дополнить логику типовой функции (выполнить предварительные действия, скорректировать параметры или обработать результат перед возвратом), мы можем использовать аннотацию &Вместо в связке с системной функцией ПродолжитьВызов().
Посмотрим на пример перехвата экспортной функции формирования печатной формы:
&Вместо("ПечатьТ7")
Функция _ПечатьТ7(МассивОбъектов, ОбъектыПечати)
// Блок действий "Перед"
// Здесь можно проверить или модифицировать входные параметры
Если МассивОбъектов.Количество() = 0 Тогда
ВызватьИсключение "Не выбраны объекты для печати!";
КонецЕсли;
// Вызов оригинальной функции конфигурации (или следующего расширения)
Результат = ПродолжитьВызов(МассивОбъектов, ОбъектыПечати);
// Блок действий "После"
// Здесь мы можем проанализировать или изменить возвращенное значение
Если Результат <> Неопределено Тогда
// Выполняем постобработку результата, например, модификацию табличного документа
КонецЕсли;
// Обязательно возвращаем результат наружу
Возврат Результат;
КонецФункции
Разберем по шагам, как работает данная конструкция:
ПродолжитьВызов() мы выполняем любой код, который требовалось поместить в «Перед». При необходимости можно изменить переданные параметры (если они передаются по ссылке).ПродолжитьВызов() передает управление исходному телу функции в основной конфигурации.Результат).ПродолжитьВызов() пишется код, который планировался для «После». Мы можем прочитать или модифицировать сформированный объект.Возврат Результат.При использовании директивы &Вместо следует помнить о нескольких критически важных моментах:
Возврат или вызвать его без переменной, функция неявно вернет значение Неопределено, что приведет к трудноуловимым ошибкам в коде конфигурации, ожидающем конкретный тип данных.ПродолжитьВызов() должны передаваться в точном соответствии с сигнатурой оригинального метода — с соблюдением порядка и количества аргументов.&Вместо в нескольких расширениях, платформа выполнит метод только из расширения с наибольшим приоритетом. Если внутри него не вызван ПродолжитьВызов(), исполнение кода остальных расширений и оригинальной функции будет заблокировано.Если логика функции сложная, и простой обертки через ПродолжитьВызов() недостаточно, рассмотрим альтернативный инструмент — «Вызвать вместо (с контролем)» (директива &ИзменениеИКонтроль).
В этом режиме тело оригинальной функции полностью копируется в расширение, а доработки вносятся с помощью специальных тегов:
&ИзменениеИКонтроль("СформироватьДанные")
Функция СформироватьДанные(Параметры)
Результат = Новый Структура;
#Вставка
// Наш дополнительный код
Результат.Вставить("ДополнительноеПоле", Истина);
#КонецВставки
Возврат Результат;
КонецФункции
Преимущество директивы &ИзменениеИКонтроль заключается в автоматическом контроле применимости: если при обновлении типовой конфигурации разработчики изменят исходный код функции, платформа выдаст предупреждение о несовпадении, предотвратив скрытые сбои логики. Однако следует учитывать ограничение: перехватить один метод через &ИзменениеИКонтроль может только одно расширение.
Проанализируем другие правила платформы, которые важно учитывать при заимствовании процедур и функций:
Экспорт. Локальные методы модулей перехватить нельзя.УстановитьПривилегированныйРежим(Истина).