Создание пользовательской функции на встроенном языке 1С
Содержание
Свою функцию в 1С пишут в Конфигураторе: объявляют конструкцией Функция … КонецФункции в подходящем модуле, добавляют ключевое слово Экспорт, если метод будут вызывать снаружи, и после сохранения обновляют конфигурацию базы данных по кнопке F7. Чаще всего общий, многоразовый код размещают в общем модуле — тогда функцию видят и серверные, и клиентские вызовы, в зависимости от флагов модуля.
Ниже — как выбрать место для кода, объявить функцию с параметрами, вернуть результат, вызвать её из другого модуля и не споткнуться на области видимости. Код во всех примерах рабочий, под платформу 8.3 и интерфейс «Такси».
Где разместить код: общий модуль, модуль объекта или форма
От места размещения зависит, кто сможет вызвать функцию и в каком контексте (на клиенте или на сервере) она выполнится. Три основных варианта.
🔹 Общий модуль. Для универсального кода, который нужен в разных местах конфигурации: расчёты, форматирование, работа с данными. Создаётся в дереве конфигурации: ветка Общие → Общие модули, по правой кнопке — Добавить. У модуля есть флаги, которые задают контекст компиляции:
Сервер— методы доступны на сервере;Клиент (управляемое приложение)— на тонком и веб-клиенте;Вызов сервера— разрешает вызывать серверные экспортные методы с клиента напрямую;Внешнее соединение— для COM-подключений;Повторное использование возвращаемых значений— кеширование результата на время сеанса или вызова.
🔹 Модуль объекта (документа, справочника, обработки). Сюда помещают логику, относящуюся к одному конкретному объекту: заполнение реквизитов, проверки перед записью. Функция из модуля объекта обычно работает с данными этого объекта через ЭтотОбъект.
🔹 Модуль формы. Код, который обслуживает конкретную форму: реакции на нажатия, обработчики событий полей. В модуле формы у каждого метода стоит директива компиляции — &НаКлиенте, &НаСервере, &НаСервереБезКонтекста. Она важнее флагов: именно директива решает, где выполнится метод.
Если функция понадобится более чем в одном месте — сразу кладите её в общий модуль. Переносить код из модуля формы позже дольше, чем написать его в общем модуле сразу.
Коротко, куда класть код:
| Где разместить | Кто может вызвать | Типичное применение |
|---|---|---|
| Общий модуль | Любой модуль конфигурации (при Экспорт) | Расчёты, форматирование, общие проверки |
| Модуль объекта | Код, работающий с этим объектом | Заполнение, проверки перед записью |
| Модуль формы | Обработчики этой формы | Реакции на действия пользователя |
Выбор упрощается так: нужно везде — общий модуль; нужно для одного справочника или документа — модуль объекта; нужно только внутри одной формы — модуль формы.
Как объявить функцию: синтаксис встроенного языка
Функция в 1С объявляется парой строк-ограничителей, между которыми лежит тело. Общий вид:
Функция ИмяФункции(Параметр1, Параметр2) Экспорт
// тело функции
Возврат Результат;
КонецФункции
Разберём элементы:
Функция…КонецФункции— обязательные границы. Пропустите закрывающую строку — компилятор выдаст ошибку о незавершённой конструкции.- Имя — на кириллице или латинице, без пробелов, не должно совпадать с именами других методов в этом же модуле. Понятное имя (
ОкруглитьДоКопеек, а неФ1) экономит время при чтении кода. Экспорт— делает функцию видимой за пределами модуля. Без этого слова метод доступен только внутри своего модуля.Возврат— отдаёт значение в точку вызова и завершает работу функции. СтрокВозвратможет быть несколько — например, по разным веткамЕсли.
Функция обязана возвращать значение — для этого и существует Возврат. Если по теме логики ничего возвращать не нужно, объявляйте не функцию, а процедуру Процедура … КонецПроцедуры. Процедуру нельзя использовать в выражении (А = МояПроцедура(); вызовет ошибку), а функцию — можно.
Формально язык 1С не требует типизации: одна функция может вернуть то число, то строку, то Неопределено в зависимости от веток кода. Это удобно, но опасно — вызывающий код должен быть готов к любому результату. Если функция дошла до КонецФункции, не встретив Возврат, она вернёт Неопределено. Поэтому для функции всегда предусматривайте явный возврат по каждой ветке, иначе получите трудноуловимую ошибку «Значение не определено» уже в месте вызова.
Простой рабочий пример — округление суммы до копеек:
Функция ОкруглитьДоКопеек(Сумма) Экспорт
Возврат Окр(Сумма, 2);
КонецФункции
Функция посложнее — собирает ФИО, аккуратно обрабатывая пустое отчество:
Функция ПолноеИмя(Фамилия, Имя, Отчество = "") Экспорт
Результат = Фамилия + " " + Имя;
Если ЗначениеЗаполнено(Отчество) Тогда
Результат = Результат + " " + Отчество;
КонецЕсли;
Возврат Результат;
КонецФункции
Здесь Отчество = "" — параметр со значением по умолчанию. При вызове его можно не указывать.
Пошагово: добавляем функцию в общий модуль
Разберём на примере, как с нуля завести общий модуль и положить в него функцию.
- Откройте конфигурацию в Конфигураторе и при необходимости снимите её с поддержки или подготовьте расширение (об этом ниже).
- В дереве конфигурации найдите ветку
Общие → Общие модули, встаньте на неё и нажмитеДобавить(илиIns). - Задайте имя модуля — например,
РаботаССуммами. Имя латиницей или кириллицей, но осмысленное. - В палитре свойств модуля проставьте флаги контекста. Для серверных расчётов достаточно
Сервер. Если функцию будут звать с клиента — добавьтеВызов сервераили вынесите клиентский код в клиентский модуль. - Откройте модуль двойным щелчком и впишите текст функции с
Экспорт. - Сохраните конфигурацию и нажмите F7 —
Обновить конфигурацию базы данных. Пока база не обновлена, новой функции в режиме1С:Предприятиеещё нет.
Если вы правите типовую конфигурацию на поддержке, не снимайте её с поддержки без необходимости — это осложнит будущие обновления. Начиная с платформы 8.3.6 собственный код удобнее добавлять через расширение конфигурации: оно хранится отдельно, типовая остаётся нетронутой, а обновления ставятся штатно. Загрузка .cfe и команда Обновить конфигурацию базы данных — два разных шага: сначала подключаете расширение, затем обновляете базу.
После обновления функция готова к вызову из других модулей конфигурации.
Вызов функции и передача параметров
Чтобы вызвать экспортную функцию общего модуля, пишут имя модуля, точку и имя функции с аргументами:
Сумма = РаботаССуммами.ОкруглитьДоКопеек(1234.567);
// Сумма = 1234.57
Если функция объявлена в том же модуле, откуда её зовут, имя модуля не нужно — достаточно имени функции.
Параметры по умолчанию передаются по ссылке. Это значит, что функция может изменить переданную переменную, и изменение «вернётся» в точку вызова:
Процедура Увеличить(Значение)
Значение = Значение + 1;
КонецПроцедуры
Счётчик = 5;
Увеличить(Счётчик);
// Счётчик стал 6
Если такое поведение нежелательно и вы хотите защитить исходную переменную, объявляйте параметр с ключевым словом Знач — тогда функция получит копию:
Функция СледующийНомер(Знач Номер)
Номер = Номер + 1;
Возврат Номер;
КонецФункции
Здесь внешняя переменная не изменится, вернётся только результат.
Несколько практических правил по параметрам:
- 📌 Параметры со значением по умолчанию ставьте в конце списка — после обязательных.
- 📌 При вызове аргументы сопоставляются по порядку, а не по имени. Нельзя «пропустить» средний необязательный параметр, не указав предыдущие.
- 📌 Жёсткого малого лимита на число параметров нет, но если их больше пяти-шести — обычно удобнее передать структуру или объект с полями, чем длинный список.
Про имена стоит договориться заранее. Называйте функции по тому, что они делают или возвращают: ОкруглитьДоКопеек, ПолноеИмя, ПолучитьКурсВалюты. Такое имя читается как фраза в месте вызова и избавляет от комментариев. Префикс по модулю (например, РаботаССуммами.) платформа подставляет сама — в имя функции его дублировать не нужно.
Обработка ошибок и отладка функции
Если внутри функции возможна исключительная ситуация — деление на ноль, обращение к несуществующему объекту, разбор некорректных данных — оберните опасный участок в Попытка … Исключение … КонецПопытки:
Функция БезопасноеДеление(Числитель, Делитель) Экспорт
Попытка
Возврат Числитель / Делитель;
Исключение
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("РаботаССуммами.Деление",
УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
Возврат Неопределено;
КонецПопытки;
КонецФункции
ИнформацияОбОшибке() возвращает объект с описанием, а ПодробноеПредставлениеОшибки() разворачивает его в читаемый текст. Запись в журнал регистрации помогает потом понять, что случилось у пользователя. Если ошибку нужно не гасить, а передать выше, используйте ВызватьИсключение без аргументов — оно повторно возбудит текущее исключение.
Попытка нужна не всегда. Если ситуацию можно проверить заранее — например, что делитель не равен нулю или что переданный объект заполнен, — лучше сделать проверку условием Если, а исключения оставить для того, что заранее не предусмотреть (сбой при обращении к файлу, внешнему сервису, несогласованные данные). Оборачивать каждую строку в Попытка «на всякий случай» не стоит: это прячет настоящие ошибки и усложняет отладку.
Отладка. Чтобы посмотреть, как функция отрабатывает на реальных данных:
- В Конфигураторе откройте модуль и поставьте точку останова на нужной строке клавишей
F9(слева от строки появится красный кружок). - Убедитесь, что в свойствах конфигурации разрешена отладка, и запустите
1С:Предприятиев режиме отладки (Отладка → Начать отладку,F5). - Когда выполнение дойдёт до точки останова, оно остановится. Шаг за шагом проходите код клавишей
F11(с заходом внутрь вызовов) илиF10(без захода). - Значения переменных смотрите в окне
Таблоили наведя курсор на переменную; разовое вычисление выражения — черезВычислить выражение(Shift+F9).
Если точка останова не срабатывает, проверьте, что отлаживается тот же сеанс и тот же контекст (клиент/сервер), где выполняется функция. Серверный код ловится, только если включена отладка серверных вызовов.
Типичные ошибки при разработке функций
Самые частые промахи — по сообщению платформы легко опознать причину.
Экспорт у метода общего модуля, ошиблись в имени модуля или функции, либо не обновили конфигурацию базы данных (F7). Проверьте написание и обновите базу.Неопределено или не того типа. Проверьте, что функция вернула ожидаемый объект, а не Неопределено.Знач в объявление параметра, чтобы работать с копией.Вызов сервера.Ещё один источник путаницы — одинаковые имена. Если в одном модуле объявить две функции с совпадающими именами, компилятор сообщит о повторном определении. Имена методов в пределах модуля должны быть уникальными.
Частые вопросы
Чем функция отличается от процедуры?
Возврат и может участвовать в выражении (А = МояФункция();). Процедура значения не возвращает и вызывается отдельной строкой. Если результат не нужен — пишите процедуру.Можно ли вызвать функцию общего модуля из модуля формы?
Экспорт. С клиентского кода формы серверную функцию зовут либо через серверную процедуру формы, либо напрямую, когда у общего модуля включён флаг Вызов сервера.Нужно ли обновлять конфигурацию базы данных после добавления функции?
Обновить конфигурацию базы данных. До обновления новой функции в рабочем режиме 1С:Предприятие ещё нет.Как сделать функцию доступной и на клиенте, и на сервере?
Вызов сервера.