Вызов процедур и функций общего модуля: экспорт, контекст, флаги модуля

· 9 мин

Содержание

Чтобы обратиться к процедуре в общем модуле 1С, объявите её со словом Экспорт и вызывайте через точку: ИмяМодуля.ИмяПроцедуры(Параметры). Работает это только там, где модуль доступен: серверный модуль виден на сервере, клиентский — на клиенте, а с клиента на сервер можно попасть лишь через модуль с флагом «Вызов сервера».

Если вызов не компилируется или падает с ошибкой «Переменная не определена», почти всегда дело в одном из трёх: нет Экспорт, модуль недоступен в текущем контексте или процедура лежит не в том модуле. Ниже — как это устроено в 1С 8.3 с управляемыми формами и как писать вызовы, чтобы они не тормозили.

Свойства общего модуля: где он виден и кто его может вызвать

Общий модуль создаётся в конфигураторе в ветке Общие → Общие модули. Его поведение задают флажки в палитре свойств. Именно они решают, откуда к процедурам модуля можно обратиться.

ФлагЧто даёт
ГлобальныйЭкспортные методы вызываются без имени модуля, как встроенные функции
Клиент (управляемое приложение)Модуль компилируется на клиенте тонкого и веб-клиента
Клиент (обычное приложение)Модуль доступен в толстом клиенте с обычными формами
СерверМодуль компилируется на сервере
Внешнее соединениеМодуль доступен при подключении через COM-соединение
Вызов сервераЭкспортные методы серверного модуля можно вызывать с клиента
ПривилегированныйКод выполняется без проверки прав текущего пользователя
Повторное использование возвращаемых значенийРезультат функций кешируется на время вызова или сеанса

Флажки комбинируются, но не произвольно. «Вызов сервера» имеет смысл только вместе с «Сервер». «Привилегированный» доступен лишь для серверного модуля без клиентских флажков.

Область видимости процедуры внутри модуля

У процедуры общего модуля два варианта видимости:

  • 🔒 без Экспорт — процедура служебная, её вызывают только другие методы этого же модуля;
  • 🔓 с Экспорт — процедура видна снаружи: из модулей форм, объектов, менеджеров, других общих модулей.
// Общий модуль РаботаСКонтрагентами (флаг «Сервер»)

Функция ИННЗаполненКорректно(ИНН) Экспорт
	Возврат ДлинаИННДопустима(СокрЛП(ИНН));
КонецФункции

Функция ДлинаИННДопустима(ИНН)
	Возврат СтрДлина(ИНН) = 10 Или СтрДлина(ИНН) = 12;
КонецФункции

Здесь снаружи доступна только ИННЗаполненКорректно. Вспомогательная ДлинаИННДопустима в контекстной подсказке после точки не появится.

Глобальный модуль: когда имя не нужно

Если у модуля стоит флаг «Глобальный», его экспортные методы вызываются просто по имени: ИННЗаполненКорректно(ИНН). Удобно, но есть цена. Глобальные модули компилируются при старте сеанса, и каждый лишний такой модуль замедляет запуск. Второй минус — конфликт имён: две одинаковые процедуры в разных глобальных модулях не дадут сохранить конфигурацию .

В типовых конфигурациях глобальных модулей немного, и в имени у них есть слово Глобальный. Для своего кода лучше обычный модуль с вызовом через точку: так сразу видно, откуда взялся метод.

Синтаксис вызова процедур и функций общего модуля

Базовая форма одна для процедур и функций:

// Процедура — просто вызов
РаботаСКонтрагентами.ОбновитьРеквизиты(Контрагент);

// Функция — результат присваивается переменной или сразу используется
Если РаботаСКонтрагентами.ИННЗаполненКорректно(Объект.ИНН) Тогда
	Сообщить("ИНН в порядке");
КонецЕсли;

Функцию можно вызвать как процедуру — возвращаемое значение просто отбросится. Обратное не работает : процедура ничего не возвращает, и запись Результат = Модуль.Процедура() не пройдёт проверку синтаксиса.

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

Необязательные параметры объявляют со значением по умолчанию. При вызове их можно опустить или пропустить запятой:

Процедура Записать(Объект, Проверять = Истина, Комментарий = "") Экспорт
	// ...
КонецПроцедуры

РаботаСДокументами.Записать(Док);              // оба по умолчанию
РаботаСДокументами.Записать(Док, , "Импорт");  // второй пропущен

Знач и передача по ссылке

По умолчанию параметр передаётся по ссылке: если процедура изменит переменную, вызывающий код увидит новое значение. Ключевое слово Знач перед именем параметра передаёт копию. Внутри одного контекста разница чаще смысловая. На границе клиент — сервер она становится вопросом скорости, об этом ниже.

Как быстро найти нужную процедуру

  • ⌨️ наберите имя модуля и точку — контекстная подсказка покажет только экспортные методы;
  • 🔍 на вызове нажмите F12 (переход к определению), чтобы открыть код процедуры;
  • 📑 в открытом модуле список процедур показывает команда Ctrl+Alt+P.

Клиент и сервер: откуда какую процедуру можно вызвать

Это главный источник ошибок. Код формы и общих модулей исполняется в двух местах — на клиенте и на сервере. Модуль виден только в том контексте, для которого он скомпилирован.

Откуда вызываемКакой общий модуль доступен
Клиентская процедура формы (&НаКлиенте)Клиентские модули; серверные — только с флагом «Вызов сервера»
Серверная процедура формы (&НаСервере, &НаСервереБезКонтекста)Серверные модули
Модуль объекта, модуль менеджераСерверные модули
Клиентский общий модульДругие клиентские модули и модули с «Вызов сервера»
Серверный общий модульДругие серверные модули
Модуль с флагами «Клиент» и «Сервер»Только то, что доступно в обоих контекстах

С сервера клиентский модуль вызвать нельзя. Если нужна реакция на клиенте после серверной работы, верните результат в клиентскую процедуру и уже там вызовите клиентский метод.

Три способа добраться с клиента до сервера

  1. Серверная процедура формы. Пишем &НаСервере или &НаСервереБезКонтекста в модуле формы, а внутри неё обращаемся к серверному общему модулю. Подходит, когда нужны данные формы.
  2. Модуль с флагом «Вызов сервера». Клиентский код вызывает его напрямую: РаботаСКонтрагентамиВызовСервера.ПолучитьДанные(Ссылка). Без лишней процедуры в форме.
  3. Клиент-серверный модуль. Флаги «Клиент» и «Сервер» одновременно. Это не вызов сервера: код просто компилируется в обоих местах. Годится для вычислений без обращения к базе — строки, даты, проверка формата ИНН.
&НаКлиенте
Процедура ИННПриИзменении(Элемент)
	Если Не РаботаСКонтрагентамиКлиентСервер.ФорматИННВерный(Объект.ИНН) Тогда
		ОбщегоНазначенияКлиент.СообщитьПользователю("Неверный формат ИНН");
		Возврат;
	КонецЕсли;
	ЗаполнитьПоИНННаСервере();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьПоИНННаСервере()
	РаботаСКонтрагентами.ЗаполнитьРеквизитыПоИНН(Объект);
КонецПроцедуры

Через модуль с «Вызов сервера» передаются только сериализуемые значения: примитивы, ссылки, структуры, массивы, таблицы значений. Форму, элемент формы или объект справочника туда не передать. Нужны данные объекта — передайте ссылку или используйте серверную процедуру формы.

Суффиксы в именах модулей

В типовых конфигурациях и в стандартах разработки контекст модуля видно по имени:

  • Клиент — клиентский модуль;
  • Сервер или без суффикса — серверный;
  • ВызовСервера — серверный с флагом «Вызов сервера»;
  • КлиентСервер — компилируется в обоих контекстах;
  • ПолныеПрава — привилегированный;
  • ПовтИсп — с повторным использованием возвращаемых значений.

Придерживайтесь той же схемы в своём коде. По имени ЗаказыВызовСервера любой разработчик сразу поймёт, откуда модуль можно вызвать.

Работа с менеджерами объектов и записей из общего модуля

Серверный общий модуль — обычное место для кода, который читает и пишет данные. Там доступны все менеджеры конфигурации: Справочники, Документы, РегистрыСведений, РегистрыНакопления и другие.

// Общий модуль ЦеныСервер (флаг «Сервер»)
Процедура УстановитьЦену(Номенклатура, Дата, Цена) Экспорт
	Запись = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();
	Запись.Период = Дата;
	Запись.Номенклатура = Номенклатура;
	Запись.Цена = Цена;
	Запись.Записать();
КонецПроцедуры

Имена регистра и его полей здесь условные — подставьте свои из дерева метаданных.

Экспортные методы модуля менеджера

Процедуры можно класть не только в общий модуль, но и в модуль менеджера конкретного объекта. Тогда вызов идёт через менеджер:

Справочники.Контрагенты.ЗаполнитьПоИНН(Объект);
Документы.РеализацияТоваров.СформироватьПечатнуюФорму(Ссылка);

Правило простое. Код про один объект метаданных — в модуль его менеджера. Код, который нужен многим объектам, — в общий модуль. Модуль менеджера тоже должен вызываться на сервере: с клиента к нему не обратиться.

Методы модуля объекта

Экспортная процедура в модуле объекта вызывается у конкретного экземпляра:

СправочникОбъект = Ссылка.ПолучитьОбъект();
СправочникОбъект.ПересчитатьСуммы();
СправочникОбъект.Записать();

Как сделать вызовы быстрее

Сам вызов процедуры внутри одного контекста почти ничего не стоит. Дорого другое — переход между клиентом и сервером и повторные обращения к базе.

Сокращайте серверные вызовы

Каждый вызов с клиента на сервер — это сетевой запрос. В цикле на 500 строк 500 вызовов дадут заметную задержку, особенно через интернет . Соберите данные в массив или структуру и отправьте одним вызовом:

&НаКлиенте
Процедура ПроверитьВсе(Команда)
	Ссылки = Новый Массив;
	Для Каждого Строка Из Объект.Товары Цикл
		Ссылки.Добавить(Строка.Номенклатура);
	КонецЦикла;
	Результат = ТоварыВызовСервера.ПроверитьОстатки(Ссылки);
КонецПроцедуры

Ставьте Знач у параметров серверных вызовов

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

Кешируйте результаты функций

Флаг «Повторное использование возвращаемых значений» кеширует результат экспортных функций модуля. Варианты:

  • На время вызова — кеш живёт, пока выполняется серверный вызов;
  • На время сеанса — кеш живёт до конца сеанса пользователя, но платформа может очищать его раньше.

Подходит для редко меняющихся данных: настройки, константы, курсы на дату. Параметры и результат должны быть неизменяемыми — примитивы, ссылки, ФиксированныйМассив, ФиксированнаяСтруктура. Сбросить кеш вручную можно методом ОбновитьПовторноИспользуемыеЗначения().

Не кешируйте функции, которые возвращают изменчивые данные, например остатки. Пользователь увидит устаревшую цифру и не поймёт, почему.

Не делайте модули глобальными без нужды

Глобальный модуль компилируется при старте сеанса, даже если его методы ни разу не вызовутся. Обычный модуль платформа загружает при первом обращении.

Динамический вызов и вызов из внешних обработок

Иногда имя модуля известно только во время работы: подсистема может отсутствовать во внедрённой конфигурации. В конфигурациях на БСП для этого есть функция получения модуля по имени:

Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
	МодульУправлениеПечатью = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатью");
	МодульУправлениеПечатью.ВывестиТабличныйДокумент(...);
КонецЕсли;

На клиенте аналог — ОбщегоНазначенияКлиент.ОбщийМодуль. Код компилируется, даже если модуля в конфигурации нет: имя проверяется только при выполнении.

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

Внешняя обработка и расширение

Модуль внешней обработки или отчёта видит общие модули конфигурации так же, как её собственный код: серверная часть — серверные модули, клиентская — клиентские и «Вызов сервера». Расширение конфигурации тоже может вызывать экспортные методы основной конфигурации напрямую.

Ошибки при вызове процедуры общего модуля

Диагностика: выберите симптом

Ещё три ловушки

  • 🔁 Циклический вызов. Модуль А вызывает Б, а Б — снова А. Платформа это допускает, но легко получить бесконечную рекурсию и ошибку переполнения стека.
  • 🔐 Привилегированный модуль как обход прав. Код в нём игнорирует роли пользователя. Выносите туда только минимальный фрагмент, а проверку допустимости действия делайте до вызова.
  • 🧩 Флаги «Клиент» и «Сервер» у модуля, который читает базу. На клиенте запросы недоступны, и такой модуль не скомпилируется. Обращение к базе разделите по разным модулям.

Частые вопросы

Можно ли вызвать процедуру общего модуля из запроса или СКД?
Нет. Язык запросов не вызывает методы встроенного языка. Обработайте результат запроса в коде или используйте вычисляемые поля и функции выражений СКД.
Можно ли вызвать общий модуль из регламентного задания?
Да. Регламентное задание указывает именно экспортную процедуру серверного общего модуля, и выполняется она на сервере.
Чем общий модуль отличается от модуля менеджера?
Модуль менеджера привязан к одному объекту метаданных и вызывается через Справочники.Имя. Общий модуль не привязан ни к чему и вызывается по своему имени.
Как вызвать общий модуль через COM-соединение?
Включите у модуля флаг «Внешнее соединение». Затем обращайтесь через объект соединения: Соединение.ИмяМодуля.ИмяПроцедуры().
Почему процедура не видна в контекстной подсказке?
Подсказка показывает только экспортные методы, доступные в текущем контексте. Проверьте Экспорт и флаги модуля для клиента или сервера.