Вызов функций во встроенном языке 1С 8.3: от обычного вызова до кода из строки
Содержание
Чтобы выполнить функцию в 1С, её вызывают по имени со скобками и присваивают результат переменной: Итог = СуммаСНДС(1000, 20);. Если имя функции известно только во время работы программы, его собирают в строку и передают в Вычислить() — метод вернёт значение. Процедуры и несколько операторов подряд выполняют через Выполнить(), но она ничего не возвращает.
Дальше всё упирается в контекст: где выполняется код (клиент или сервер), откуда взята функция (модуль формы, общий модуль, внешняя обработка) и под какими правами. Примеры написаны для платформы 8.3 и управляемых форм, они одинаково работают в типовых и самописных конфигурациях. Имя модуля МойМодульСервер условное — подставьте свой общий модуль.
Прямой вызов и вызов функции по имени из строки
Обычный вызов — самый быстрый и надёжный. Компилятор проверяет имя ещё до запуска, ошибка в названии видна сразу при синтаксическом контроле.
// Общий модуль МойМодульСервер (флаги: Сервер)
Функция СуммаСНДС(Сумма, Ставка) Экспорт
Возврат Сумма + Окр(Сумма * Ставка / 100, 2);
КонецФункции
// Вызов из другого серверного кода
Итог = МойМодульСервер.СуммаСНДС(1000, 20); // 1200
Что нужно для вызова из другого модуля:
- 🔑 ключевое слово
Экспортпосле списка параметров; - 📦 имя модуля перед точкой. Исключение — общий модуль с флагом
Глобальный: его экспортные функции вызывают без префикса; - 🧩 у объекта (документа, справочника) функцию модуля объекта вызывают через сам объект:
ДокОбъект = Ссылка.ПолучитьОбъект(); ДокОбъект.ПроверитьЗаполнениеСумм();.
Вычислить: выражение из строки с возвратом значения
Вычислить(Строка) разбирает строку как выражение и возвращает его значение. Внутри строки видны локальные переменные и параметры того места, откуда метод вызван.
ИмяФункции = "МойМодульСервер.СуммаСНДС";
Сумма = 1000;
Ставка = 20;
Итог = Вычислить(ИмяФункции + "(Сумма, Ставка)"); // 1200
Так строят настраиваемые алгоритмы: имя функции хранится в справочнике или константе, код его подставляет.
Выполнить: операторы из строки
Выполнить(Строка) запускает один или несколько операторов. Значения она не возвращает, зато может присвоить его локальной переменной.
Итог = 0;
Выполнить("Итог = МойМодульСервер.СуммаСНДС(Сумма, Ставка);");
| Способ | Что возвращает | Когда брать | Риск |
|---|---|---|---|
| Прямой вызов | Значение функции | Имя известно заранее | Минимальный |
Вычислить() | Значение выражения | Имя функции в данных | Ошибку видно только при запуске |
Выполнить() | Ничего | Нужно вызвать процедуру или блок кода | Строка может содержать любой код |
В конфигурациях на БСП есть ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяМетода, Параметры). Он проверяет, что строка — именно имя метода, а не произвольный код. Если имя приходит из данных, берите его вместо голой Выполнить().
Как выполнить серверную функцию из клиентского кода
В управляемой форме код делится директивами компиляции. Обработчик кнопки работает на клиенте. Запрос к базе, запись объекта, обращение к регистрам — только на сервере.
&НаКлиенте
Процедура Рассчитать(Команда)
Объект.СуммаИтого = РассчитатьНаСервере(Объект.Сумма);
КонецПроцедуры
&НаСервереБезКонтекста
Функция РассчитатьНаСервере(Сумма)
Возврат МойМодульСервер.СуммаСНДС(Сумма, 20);
КонецФункции
Какую директиву выбрать:
| Директива | Что уходит на сервер | Когда использовать |
|---|---|---|
&НаСервере | Все данные формы | Нужно менять реквизиты формы на сервере |
&НаСервереБезКонтекста | Только параметры | Расчёт по переданным значениям |
Общий модуль с флагами Сервер + Вызов сервера | Только параметры | Функция нужна многим формам |
Пара правил, о которые спотыкаются чаще всего:
- Клиентский код не видит общий модуль без флага
Вызов сервера. Функции такого модуля вызывают из серверной процедуры формы. - Параметры уходят на сервер копией. Изменение параметра внутри серверной функции на клиенте не отразится — возвращайте результат через
Возвратили структуру. - На сервер передаются только сериализуемые значения: примитивы, ссылки, структуры, массивы, таблицы значений через данные формы. Объект формы или элемент формы туда не передать.
Отложенный, фоновый и асинхронный запуск
Иногда функцию нужно выполнить не прямо сейчас. Для этого в платформе три механизма.
Через паузу на клиенте
ПодключитьОбработчикОжидания("ОбновитьСтатус", 2, Истина) вызовет клиентскую процедуру формы ОбновитьСтатус через 2 секунды один раз. Третий параметр Ложь — повторять каждые 2 секунды, пока не отключите методом ОтключитьОбработчикОжидания. Процедура должна быть без параметров.
В фоновом задании на сервере
Долгий расчёт не должен держать интерфейс. Его запускают фоном:
Параметры = Новый Массив;
Параметры.Добавить(НачалоМесяца(ТекущаяДатаСеанса()));
Задание = ФоновыеЗадания.Выполнить("МойМодульСервер.ПересчитатьОстатки",
Параметры, , "Пересчёт остатков");
Метод должен быть экспортным, лежать в серверном общем модуле и вызываться из серверного кода. Фоновое задание не возвращает значение напрямую: результат кладут во временное хранилище. В БСП это уже обёрнуто в модуль ДлительныеОперации — функции ВыполнитьФункцию и ВыполнитьПроцедуру сами создают задание и хранилище.
Ход заданий видно в режиме «Предприятие»: в конфигурациях на БСП — Администрирование → Обслуживание → Регламентные и фоновые задания.
Асинхронно с ожиданием
С платформы 8.3.18 функции можно объявлять с Асинх и ждать результата оператором Ждать. Так удобно писать диалоги без обработчиков оповещения:
&НаКлиенте
Асинх Процедура Очистить(Команда)
Ответ = Ждать ВопросАсинх("Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
Объект.Товары.Очистить();
КонецЕсли;
КонецПроцедуры
Выполнение функции из внешней обработки
Внешняя обработка (.epf) — способ выполнить свой код в чужой базе без изменения конфигурации. Функцию в модуле объекта обработки объявляют с Экспорт, потом подключают файл на сервере.
Порядок такой:
- На клиенте поместите файл во временное хранилище (например, методом
НачатьПомещениеФайлаНаСервер) и получите адрес. - На сервере подключите обработку и создайте объект.
- Вызовите экспортную функцию объекта.
&НаСервере
Функция ВыполнитьИзВнешней(АдресВХранилище)
ИмяОбработки = ВнешниеОбработки.Подключить(АдресВХранилище, , Истина);
Обработка = ВнешниеОбработки.Создать(ИмяОбработки);
Возврат Обработка.РассчитатьИтог(1000);
КонецФункции
Третий параметр Истина включает безопасный режим. В нём обработка не получит доступа к файлам сервера, COM-объектам и привилегированному режиму. Выключайте его только для собственных проверенных файлов.
Если обработку нужно запускать регулярно, удобнее зарегистрировать её в базе. В БП 3.0, ЗУП 3.1 и УТ 11 это делается в Администрирование → Печатные формы, отчеты и обработки → Дополнительные отчеты и обработки. Регистрация позволяет назначить обработку разделам, дать права отдельным пользователям и запускать по расписанию.
Внешняя обработка выполняет код с правами того, кто её запустил. Не открывайте .epf из писем и чатов в рабочей базе, сначала проверьте её на копии.
Ошибки при выполнении функции: перехват и отладка
Код из строки компилируется в момент вызова. Опечатка в имени функции не поймается синтаксическим контролем — программа упадёт у пользователя. Поэтому Вычислить() и Выполнить() почти всегда оборачивают в попытку:
Попытка
Итог = Вычислить(ИмяФункции + "(Сумма, Ставка)");
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("Расчёт.Формула", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(Инфо));
ВызватьИсключение КраткоеПредставлениеОшибки(Инфо);
КонецПопытки;
Логика простая: подробности с номером строки и стеком — в журнал регистрации, пользователю — короткий текст. Пустой блок Исключение без записи ошибки прячет проблему, так не делайте.
Как посмотреть, что реально выполняется
- 🐞 Поставьте точку останова клавишей
F9и запустите отладку из конфигуратора (Отладка → Начать отладку). - 🔍 На остановке выделите выражение и нажмите
Shift+F9— окно «Вычислить выражение» покажет значение и даже вызовет функцию с вашими параметрами. - 🖥 Для серверного кода в клиент-серверной базе отладку нужно разрешить на сервере 1С: агент запускают с ключом
-debug. Перезапуск службы обрывает сеансы пользователей — делайте это вне рабочего времени.
Скорость: сколько стоит каждый вызов
Сама функция обычно выполняется быстро. Время съедают обвязка и количество вызовов.
| Что замедляет | Почему | Что сделать |
|---|---|---|
| Вызов сервера в цикле на клиенте | Каждый вызов — отдельный обмен по сети | Собрать данные в массив и вызвать сервер один раз |
&НаСервере вместо &НаСервереБезКонтекста | На сервер и обратно гоняются все данные формы | Передавать только нужные значения |
Вычислить() в цикле на 10 000 строк | Строка компилируется заново на каждой итерации | Вычислить имя один раз, вызывать напрямую или через Соответствие готовых результатов |
| Повторное чтение неизменных данных | Один и тот же запрос на каждый вызов | Общий модуль с повторным использованием «На время сеанса» или «На время вызова» |
Пример: форма проверяет цены 200 строк, и для каждой вызывает серверную функцию. При 30 мс на обмен это 6 секунд ожидания. Одна функция, получившая массив из 200 товаров, вернёт ответ за один обмен.
Где искать узкие места: запустите отладку и включите Отладка → Замер производительности. Замер покажет, какие строки модуля съели время и сколько раз они выполнялись.
Модуль с повторным использованием возвращаемых значений не должен отдавать изменяемые объекты. Если функция вернула массив, а вызывающий код его изменил, изменённый массив получат и следующие вызовы из кеша.
Безопасный режим и права при выполнении функций
Строка в Выполнить() — это любой код. Если текст пришёл от пользователя или из данных, он может удалить документы, прочитать файлы сервера или запустить внешнюю программу. Защита строится в три слоя.
1. Безопасный режим
УстановитьБезопасныйРежим(Истина);
Результат = Вычислить(ТекстФормулы);
В безопасном режиме код не может включить привилегированный режим, работать с файлами, COM-объектами и внешними компонентами. Режим действует до выхода из текущей процедуры, поэтому формулу удобно вычислять в отдельной маленькой функции. В БСП для этого есть готовые ОбщегоНазначения.ВычислитьВБезопасномРежиме и ОбщегоНазначения.ВыполнитьВБезопасномРежиме.
2. Права пользователя
Серверная функция выполняется с правами текущего пользователя, включая ограничения на уровне записей. Поэтому один и тот же вызов у двух бухгалтеров может вернуть разные суммы.
Когда нужно прочитать данные в обход прав (например, служебную настройку), используют УстановитьПривилегированныйРежим(Истина) только на сервере или общий модуль с флагом Привилегированный. Держите такой код коротким и не принимайте в нём строки для Выполнить().
3. Профили безопасности кластера
В клиент-серверном варианте администратор может назначить базе профиль безопасности в консоли кластера. Профиль ограничивает доступ к файловой системе, COM, внешним компонентам и интернет-ресурсам для всей базы, а не для одной функции.