Процедуры во встроенном языке 1С 8.3: объявление, параметры, вызов

· 9 мин

Содержание

Чтобы добавить процедуру в 1С, откройте нужный модуль в Конфигураторе и напишите блок Процедура ИмяПроцедуры() ... КонецПроцедуры. Если её будут вызывать из другого модуля, допишите после скобок Экспорт, а в модуле формы поставьте над ней директиву &НаКлиенте или &НаСервере.

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

Где добавить процедуру: выбор модуля в Конфигураторе

Сначала решите, в каком модуле будет жить код. От этого зависит, откуда процедуру можно вызвать и где она выполнится — на клиенте или на сервере.

МодульКак открытьДля чего
Модуль формыОткрыть форму → вкладка Модуль внизу редактораОбработчики кнопок, полей, событий формы
Модуль объектаПравый клик по справочнику или документу → Открыть модуль объектаЛогика одного элемента: проверки, заполнение, ПередЗаписью
Модуль менеджераПравый клик → Открыть модуль менеджераДействия над всем справочником: поиск, печать, служебные выборки
Общий модульВетка Общие → Общие модули → ДобавитьКод, который нужен в разных местах конфигурации
Модуль приложенияПравый клик по корню конфигурации → Открыть модуль управляемого приложенияСобытия запуска и завершения программы

Пошагово: новая процедура в общем модуле

  1. Откройте базу в режиме Конфигуратор и выберите Конфигурация → Открыть конфигурацию.
  2. В дереве раскройте Общие → Общие модули, нажмите Добавить.
  3. Задайте имя, например РаботаСТоварами, и отметьте флаги исполнения: Сервер, Клиент (управляемое приложение), при необходимости Вызов сервера.
  4. Двойным щелчком откройте модуль и напишите процедуру.
  5. Сохраните конфигурацию и обновите конфигурацию базы данных (F7).

Обработчик события формы — без ручного набора

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

  1. Выделите элемент формы или команду и откройте свойства (Alt+Enter).
  2. Перейдите в группу События и нажмите кнопку с лупой напротив нужного события.
  3. Для команды платформа спросит, как создать обработчик: только на клиенте, на клиенте и процедура на сервере, на клиенте и процедура на сервере без контекста.

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

Если модуль большой, раскладывайте процедуры по областям #Область ИмяОбласти ... #КонецОбласти. В типовых конфигурациях приняты области ПрограммныйИнтерфейс, СлужебныйПрограммныйИнтерфейс и СлужебныеПроцедурыИФункции — по ним сразу видно, что можно вызывать снаружи.

Синтаксис объявления процедуры в модуле 1С

Общий вид объявления:

&НаСервере
Процедура ИмяПроцедуры(Параметр1, Знач Параметр2, Параметр3 = 0) Экспорт

	Перем ЛокальнаяПеременная;

	// операторы

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

Что здесь обязательно, а что нет:

  • 🔹 Процедура и КонецПроцедуры — обязательны. Английский вариант: Procedure ... EndProcedure.
  • 🔹 Имя — обязательно. Начинается с буквы или подчёркивания, без пробелов. Принято писать слитно с заглавных: ЗаполнитьТабличнуюЧасть.
  • 🔹 Скобки — обязательны, даже если параметров нет: Процедура Обновить().
  • 🔹 Экспорт — по желанию, открывает процедуру для других модулей.
  • 🔹 Директива компиляции — нужна в модулях форм и команд, в модуле объекта не используется.
  • 🔹 Перем внутри процедуры — по желанию. Локальная переменная создаётся и простым присваиванием Сумма = 0;.

Порядок разделов модуля

У модуля жёсткая структура. Нарушите её — получите ошибку компиляции:

  1. Раздел объявления переменных модуля (Перем ... ;).
  2. Раздел процедур и функций.
  3. Раздел основной программы — операторы вне процедур, выполняются при создании модуля.

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

Досрочный выход

Оператор Возврат; прерывает процедуру в любом месте. Значение после него в процедуре писать нельзя.

Процедура ПроверитьКонтрагента(Контрагент)

	Если НЕ ЗначениеЗаполнено(Контрагент) Тогда
		Сообщить("Не указан контрагент");
		Возврат;
	КонецЕсли;

	// основная проверка

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

Параметры процедуры: по ссылке, Знач и значения по умолчанию

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

Процедура Удвоить(Число)
	Число = Число * 2;
КонецПроцедуры

А = 5;
Удвоить(А);
// А = 10

Ключевое слово Знач перед параметром включает передачу по значению: процедура получает копию.

Процедура Удвоить(Знач Число)
	Число = Число * 2;
КонецПроцедуры

А = 5;
Удвоить(А);
// А = 5, исходная переменная не изменилась

Ловушка со Знач и коллекциями

Для структур, массивов, таблиц значений и объектов Знач копирует ссылку, а не сам объект. Присвоить параметру новый массив без последствий можно. А вот добавленный элемент увидит и вызывающий код.

Процедура Дополнить(Знач Список)
	Список.Добавить("новый");   // изменит исходный массив
	Список = Новый Массив;      // исходный массив не тронет
КонецПроцедуры

Необязательные параметры

Параметру можно задать значение по умолчанию. Тогда при вызове его разрешено пропустить:

Процедура ЗаписатьВЖурнал(Текст, Уровень = "Информация", Важно = Ложь)
	// ...
КонецПроцедуры

ЗаписатьВЖурнал("Старт обмена");
ЗаписатьВЖурнал("Ошибка", , Истина); // второй параметр пропущен

Значение по умолчанию — только литерал: число, строка, дата, Истина, Ложь, Неопределено, Null. Вызов функции или Новый Структура там не допускаются. Если нужна пустая структура по умолчанию, ставьте Неопределено и создавайте её внутри.

Сколько параметров — нормально

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

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

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

Экспорт

Без Экспорт процедура видна только внутри своего модуля. С ним — из других модулей через объект или имя модуля:

Где объявленаКак вызвать снаружи
Общий модуль РаботаСТоварамиРаботаСТоварами.ПересчитатьЦены(Документ);
Модуль менеджера справочникаСправочники.Номенклатура.ЗагрузитьИзФайла(Путь);
Модуль объекта документаДокументОбъект.ЗаполнитьПоОснованию(Основание);
Глобальный общий модульПересчитатьЦены(Документ); — без имени модуля

Директивы компиляции в модуле формы

ДирективаГде выполняетсяДоступ к данным формы
&НаКлиентеНа клиентеДа
&НаСервереНа сервереДа, форма передаётся на сервер
&НаСервереБезКонтекстаНа сервереНет, только параметры
&НаКлиентеНаСервереБезКонтекстаТам, откуда вызвалиНет

Процедура без директивы в модуле формы считается &НаСервере. Пишите директиву явно — так код читают без догадок.

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

Флаги общего модуля

  • 🖥️ Сервер — код компилируется на сервере.
  • 💻 Клиент (управляемое приложение) — доступен на клиенте.
  • 🔄 Вызов сервера — экспортные процедуры серверного модуля можно вызвать с клиента.
  • 🌐 Глобальный — процедуры вызываются без имени модуля. Злоупотреблять не стоит: такие модули компилируются при старте программы.
  • 🔐 Привилегированный — код выполняется без проверки прав. Включайте точечно.

Как вызвать процедуру из формы, модуля объекта и с клиента

Вызов — это имя, скобки и аргументы через запятую:

ПересчитатьИтоги();
РаботаСТоварами.ПересчитатьЦены(Объект.Ссылка, Истина);

С клиента на сервер в форме

Типичная связка: кнопка срабатывает на клиенте, тяжёлая работа уходит на сервер.

&НаКлиенте
Процедура Заполнить(Команда)
	ЗаполнитьНаСервере();
	Элементы.Товары.Обновить();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьНаСервере()
	ДокументОбъект = РеквизитФормыВЗначение("Объект");
	ДокументОбъект.ЗаполнитьТовары();
	ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры

Здесь ЗаполнитьТовары — экспортная процедура модуля объекта. Из серверной процедуры формы она доступна после получения объекта.

Вызов из модуля объекта или менеджера

С клиента напрямую вызвать процедуру модуля объекта нельзя. Сначала перейдите на сервер — через &НаСервере в форме или через общий модуль с флагом Вызов сервера.

Отложенный вызов по имени

Иногда процедуру вызывают не напрямую:

  • ⏱️ ПодключитьОбработчикОжидания("ОбновитьСтатус", 5) — клиентская процедура формы запустится через 5 секунд. Третий параметр Истина делает вызов однократным.
  • 📨 Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект) — процедура ПослеВопроса сработает, когда пользователь ответит в ПоказатьВопрос. Обработчик должен быть экспортным.

Асинхронные процедуры

В платформе 8.3.18 и выше появились Асинх и Ждать. Процедура с модификатором Асинх может дождаться ответа пользователя прямо в теле:

&НаКлиенте
Асинх Процедура Удалить(Команда)
	Ответ = Ждать ВопросАсинх("Удалить строку?", РежимДиалогаВопрос.ДаНет);
	Если Ответ = КодВозвратаДиалога.Да Тогда
		// удаление
	КонецЕсли;
КонецПроцедуры

Процедура или функция: в чём разница

Разница одна по сути: функция возвращает значение, процедура — нет.

ПризнакПроцедураФункция
Ключевые словаПроцедура ... КонецПроцедурыФункция ... КонецФункции
Возврат значенияНет, только Возврат;Возврат Значение;
Использование в выраженииНельзяИтог = Сумма(А, Б);
Вызов как операторДаДа, результат отбрасывается
Обработчики событийПочти всегда процедурыРедко

Когда что выбирать:

  • ✅ Процедура — действие: записать, заполнить, пересчитать, показать.
  • ✅ Функция — вопрос: получить, найти, проверить, вычислить.

Хорошее правило — имя подсказывает тип. ЗаполнитьТовары — процедура, ПолучитьОстаток — функция. Если процедура должна вернуть несколько результатов, передайте параметр по ссылке или сделайте функцию, возвращающую структуру. Второй вариант читается проще.

Ошибки при создании процедур и как их исправить

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

Ещё несколько промахов, которые не дают текста ошибки, но ломают логику:

  • ⚠️ Обработчик не привязан к событию. Процедура есть, но в свойствах элемента формы поле события пустое. Код просто не запускается.
  • ⚠️ Серверный вызов в цикле. &НаСервере внутри клиентского цикла на 500 строк — это 500 обращений к серверу. Соберите данные и вызовите сервер один раз.
  • ⚠️ Параметр по ссылке меняется случайно. Процедура «подчищает» входную строку, а вызывающий код потом работает с изменённым значением. Защищайтесь через Знач.
  • ⚠️ Правка типовой конфигурации напрямую. Новую процедуру в типовую базу лучше добавить в расширение: при обновлении она не потеряется. Расширения доступны с платформы 8.3.6.

Изменения в модулях общих объектов требуют обновления конфигурации базы данных. Делайте его в нерабочее время и после резервной копии, если рядом меняется структура метаданных.

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

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