Как получить общий модуль по его имени в 1С:Предприятие 8.3

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

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

Проблема: Метаданные против Контекста

Первое, с чем сталкиваются разработчики — это путаница между объектом метаданных и программным контекстом модуля. Проанализируем типичную ошибку. Если мы попытаемся обратиться к модулю через коллекцию метаданных:


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

Выясним причину: Метаданные.ОбщиеМодули возвращает объект типа ОбъектМетаданных: Общий модуль. Этот объект содержит информацию о свойствах модуля (имя, синоним, флаги «Глобальный», «Сервер» и т.д.), но он не содержит самих экспортных процедур и функций. Для вызова кода нам нужен именно контекст исполнения.

Решение через функцию Вычислить()

Самый прямой и эффективный способ получить ссылку на контекст модуля по его имени — использование встроенной функции Вычислить() (или Eval() в англоязычном варианте). Рассмотрим простейший пример:


ИмяМодуля = "БухгалтерскийУчетПереопределяемый";
// Получаем контекст модуля
МодульКонтекст = Вычислить(ИмяМодуля);
// Теперь мы можем вызывать его методы через точку
МодульКонтекст.ОбновитьПараметры();

Разберем, почему это работает. Функция Вычислить() принимает строку и интерпретирует её как фрагмент кода на языке 1С. Поскольку имя общего модуля (если он не глобальный) является доступным идентификатором в глобальном контексте, платформа возвращает ссылку на сам объект модуля.

Безопасный вызов и проверка существования модуля

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


Функция ПолучитьМодульБезопасно(ИмяМодуля) Экспорт
    // Проверяем наличие модуля в дереве конфигурации
    Если Метаданные.ОбщиеМодули.Найти(ИмяМодуля) <> Неопределено Тогда
        Возврат Вычислить(ИмяМодуля);
    Иначе
        Возврат Неопределено;
    КонецЕсли;
КонецФункции

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


МодульБСП = ПолучитьМодульБезопасно("ОбщегоНазначения");
Если МодульБСП <> Неопределено Тогда
    Значение = МодульБСП.ЗначениеРеквизитаОбъекта(Ссылка, "Код");
КонецЕсли;

Использование инструментов БСП (Библиотеки стандартных подсистем)

Если ваша конфигурация построена на базе БСП, то изобретать велосипед не нужно. В составе библиотеки уже есть готовый инструмент в модуле ОбщегоНазначения. Рассмотрим подробнее метод ОбщийМодуль():


// В БСП это реализовано максимально надежно
НужныйМодуль = ОбщегоНазначения.ОбщийМодуль("РаботаСДоговорами");
НужныйМодуль.ПроверитьСтатус(ДоговорСсылка);

Важный нюанс: стандартная функция БСП может вызвать исключение, если модуль не найден. Если вы пишете код для внешних отчетов, которые должны работать «везде», лучше использовать комбинацию проверки метаданных и вызова Вычислить().

Обход ошибок компиляции: метод «Инъекции» для универсального кода

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

Проблема в том, что 1С проверяет синтаксис при компиляции. Если в коде есть обращение к ОбщегоНазначения.ЧтоТоТам(), а модуля ОбщегоНазначения в базе нет, обработка просто не откроется. Выясним, как обмануть компилятор, используя особенность двухпроходной проверки:


Функция СведенияОВнешнейОбработке() Экспорт
    // Обман компилятора: создаем локальные переменные с именами общих модулей
    Если Ложь Тогда
        ОбщегоНазначения = Неопределено;
        ДополнительныеОтчетыИОбработки = Неопределено;
    КонецЕсли;

    // Теперь компилятор считает, что ОбщегоНазначения - это переменная, 
    // и не ищет общий модуль при проверке синтаксиса
    ПараметрыРегистрации = Новый Структура;
    // ... заполнение параметров ...
    Возврат ПараметрыРегистрации;
КонецФункции

В блоке Если Ложь Тогда мы объявляем идентификаторы, совпадающие с именами отсутствующих модулей. Это позволяет коду пройти проверку синтаксиса, а в режиме исполнения управление по этим веткам никогда не пройдет, либо вы сможете использовать Попытка...Исключение для динамической проверки.

Производительность и безопасность (Аудит 1С:Фреш)

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

Основные правила безопасности при использовании динамических модулей:

  1. Никогда не передавайте в Вычислить() данные, полученные из полей ввода или внешних файлов без жесткой проверки.
  2. Всегда ограничивайте список доступных модулей «белым списком» или проверяйте их наличие в Метаданные.ОбщиеМодули.
  3. Помните о контексте: если модуль помечен только как Сервер, попытка выполнить Вычислить("ИмяМодуля") на клиенте вернет ошибку «Переменная не определена».
  4. Для повышения производительности в циклах: если вам нужно вызвать метод модуля 1000 раз, получите ссылку на модуль один раз в переменную ПЕРЕД циклом, а не вызывайте Вычислить() на каждой итерации.

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

← На главную