К статье
Практический материал

Разработка и Конфигурация · 12 мин

Процедуры и функции в 1С: что это такое и как ими пользоваться

Что такое процедуры и функции во встроенном языке 1С, чем они отличаются, как объявлять, передавать параметры и где размещать код. Примеры и типичные ошибки.

Процедуры и функции — базовые строительные блоки встроенного языка 1С. Любая логика в конфигурации, от расчёта суммы документа до формирования отчёта, оформляется именно через них. Понимание разницы между ними и правил их размещения — первое, что нужно освоить при доработке типовых конфигураций или написании собственных модулей.

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

Грамотное разбиение кода на процедуры и функции решает три задачи: устраняет дублирование одинаковых фрагментов, упрощает тестирование отдельных алгоритмов и делает конфигурацию понятнее для тех, кто будет её сопровождать. Ниже разберём синтаксис, правила размещения в модулях, передачу параметров и ошибки, которые чаще всего встречаются у начинающих разработчиков.

Как объявить процедуру и функцию: синтаксис

Объявление начинается с ключевого слова Процедура или Функция, затем идёт имя, в скобках — список параметров, далее тело и завершающее слово КонецПроцедуры или КонецФункции. Имя должно начинаться с буквы, не содержать пробелов и не совпадать с ключевыми словами языка.

Функция РассчитатьЦенуСНДС(Цена, СтавкаНДС) Экспорт

Возврат Цена + Цена * СтавкаНДС / 100;

КонецФункции

Процедура ЗаписатьЛогОперации(ТекстСообщения) Экспорт

ЗаписьЖурналаРегистрации(ТекстСообщения);

КонецПроцедуры

Если функция завершится без выполнения оператора Возврат, платформа выдаст ошибку уже на этапе проверки модуля. В процедуре оператор Возврат тоже допустим, но без значения — он просто досрочно завершает выполнение, что удобно для выхода при невыполненном условии.

Переменные, объявленные внутри тела через Перем или созданные присваиванием, локальны: снаружи они недоступны и не конфликтуют с одноимёнными переменными других процедур. Это позволяет безопасно использовать короткие имена вроде Результат или Сч внутри каждой функции.

Чем процедура отличается от функции на практике

Формальное отличие одно — возврат значения, но из него следуют практические правила. Если результат работы нужен вызывающему коду (сумма, признак успеха, найденная ссылка), пишите функцию. Если код выполняет действие, результат которого не нужно проверять в выражении (запись в журнал, заполнение табличной части, отправка уведомления), используйте процедуру.

Функцию можно встроить прямо в выражение: Если ПроверитьЗаполнение(Документ) Тогда ... или Итого = Итого + ПолучитьСумму(Строка). Процедуру так использовать нельзя — попытка присвоить её результат переменной приведёт к ошибке компиляции модуля.

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

Что выбрать

Функция

Нужен результат вычисления или поиска: сумма, ссылка, признак Истина/Ложь. Можно встраивать в выражения и условия.

Процедура

Нужно выполнить действие без возврата значения: записать данные, заполнить объект, вывести сообщение. Вызывается отдельным оператором.

Где размещать код: виды модулей

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

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

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

Параметры: передача по значению и по ссылке

Параметры перечисляются в скобках через запятую. По умолчанию параметр передаётся по ссылке: изменения внутри процедуры затронут переданную переменную. Ключевое слово Знач перед именем параметра включает передачу по значению — внутри работает копия, исходная переменная не изменится.

Процедура УвеличитьСчетчик(Счетчик) // по ссылке

Счетчик = Счетчик + 1;

КонецПроцедуры

Функция СуммаОкругленная(Знач Сумма) // по значению

Сумма = Окр(Сумма, 2);

Возврат Сумма;

КонецФункции

Для параметра можно задать значение по умолчанию: Процедура ОтправитьОтчет(Получатель, Формат = "PDF"). Тогда вызов с одним аргументом корректен — незаполненные параметры с умолчаниями подставятся автоматически. Параметры без значения по умолчанию, если их не передали, получат значение Неопределено — это надо учитывать в проверках.

Пропуск необязательных параметров в середине списка делается запятыми: МояПроцедура(Парам1, , Парам3). Злоупотреблять этим не стоит: вызовы с несколькими пропусками трудно читать, и при добавлении нового параметра легко сместить позиции.

Коллекции (массивы, структуры, таблицы значений) всегда передаются по ссылке, даже с ключевым словом Знач — копируется только ссылка на коллекцию, а не её содержимое. Чтобы изменения внутри функции не затронули исходную таблицу, создайте её копию методом Скопировать().
ПЗ
Практическое замечание

Директивы компиляции и контекст исполнения

В модулях форм и команд перед объявлением ставится директива, определяющая контекст: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста. От неё зависит, какие объекты и методы доступны внутри: на клиенте недоступны запросы и прямая работа с базой, на сервере — элементы интерфейса и интерактивные диалоги.

Вариант &НаСервереБезКонтекста предпочтителен для серверных вызовов из формы, когда не нужны реквизиты формы: такой вызов не передаёт данные формы между клиентом и сервером и работает быстрее. Частая оптимизация — собрать все серверные обращения обработчика в одну серверную процедуру вместо нескольких отдельных вызовов, чтобы сократить число клиент-серверных обращений.

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

Контрольные точки

Как проверить корректность размещения

Вызов серверной функции из клиентской процедуры
Норма

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

Тревожный признак

Ошибка «Процедура или функция не определена» при выполнении

Обращение к базе данных (запрос, запись)
Норма

Код находится в серверном контексте

Тревожный признак

Ошибка о недопустимости операции на клиенте

Проверка модуля в конфигураторе
Норма

Проверка завершается без ошибок компиляции

Тревожный признак

Сообщения о неопределённых переменных или недопустимых директивах

Типичные ошибки при работе с процедурами и функциями

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

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

Типичные ошибки
01
Функция без Возврат в одной из веток условия — ошибка компиляции или непредсказуемый результат. Проверяйте, что Возврат выполняется на любом пути выполнения.
02
Копирование одинакового кода в несколько объектов вместо выноса в общий модуль — при доработке исправляют одну копию и получают расхождение поведения.
03
Изменение параметров-коллекций внутри функции без копии — вызывающий код получает неожиданно изменённые данные.
04
Процедуры на сотни строк с десятком обязанностей — такой код невозможно тестировать и безопасно менять; дробите на функции с одной задачей.
05
Вызов сервера в цикле из клиентского кода — резкое падение производительности; переносите весь цикл в одну серверную процедуру.

Как проверить и отладить свой код

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

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

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

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

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

Можно ли вызвать процедуру из другого общего модуля?

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

Что произойдёт, если не передать обязательный параметр?

Параметр получит значение Неопределено. Если внутри кода с ним выполняется арифметика или обращение к свойствам, возникнет ошибка выполнения. Поэтому в начале функции часто делают проверку вида «Если Параметр = Неопределено Тогда Возврат ...».

Чем директива &НаСервереБезКонтекста лучше &НаСервере?

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

Может ли функция возвращать несколько значений?

Напрямую — нет, оператор Возврат принимает одно значение. Обходные пути: вернуть структуру с несколькими полями, вернуть массив или передать часть результатов через параметры, объявленные без Знач (по ссылке). Самый читаемый вариант — структура с именованными полями.

Почему возникает ошибка «Процедура или функция с указанным именем не определена»?

Три типовые причины: метод объявлен без Экспорт и вызывается из другого модуля; в имени опечатка или несовпадение регистра в имени модуля; вызов идёт из контекста, где метод недоступен (например, клиент вызывает серверный модуль без флага «Вызов сервера»). Проверяйте именно в этом порядке.

Нужно ли описывать процедуры комментариями?

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

Итог

Что важно запомнить

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