При разработке в среде 1С часто возникает стандартная задача: мы вызываем определенную процедуру, внутри нее выполняются вычисления или запросы к базе данных (например, подсчет количества часов по задаче), и полученный результат необходимо использовать в вызывающем коде. По умолчанию процедура в 1С не возвращает никакого значения напрямую через оператор Возврат. Как же быть в такой ситуации?
В этой статье мы подробно разберем, какими способами можно передать переменную из процедуры или функции, проанализируем внутренние механизмы платформы «1С:Предприятие», влияющие на производительность, и изучим стандарты разработки фирмы 1С.
Если главной целью вашего алгоритма является расчет или получение какого-то конкретного значения, то использование процедуры методически неверно. Для таких задач в языке 1С предусмотрены функции. Функция отличается от процедуры тем, что она возвращает результат своей работы в точку вызова с помощью ключевого слова Возврат.
Давайте перепишем исходный код автора форума, превратив процедуру в функцию. Это самый простой, лаконичный и читаемый способ решения проблемы.
// Вызывающий код (например, в другой процедуре)
ИД_Задачи = "12345";
КоличествоЧасов = ПолучитьКоличествоЧасовЗадачи(ИД_Задачи);
Сообщить("Всего часов по задаче: " + КоличествоЧасов);
// Определение функции
Функция ПолучитьКоличествоЧасовЗадачи(ИД)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КоличествоЧасовЗадачБитрикс.КоличествоЧасов КАК КоличествоЧасов
|ИЗ
| РегистрСведений.КоличествоЧасовЗадачБитрикс КАК КоличествоЧасовЗадачБитрикс
|ГДЕ
| КоличествоЧасовЗадачБитрикс.ID = &ИД";
Запрос.УстановитьПараметр("ИД", ИД);
РезультатЗапроса = Запрос.Выполнить();
Таб = РезультатЗапроса.Выгрузить();
ВозвращаемоеЗначение = Таб.Итог("КоличествоЧасов");
Возврат ВозвращаемоеЗначение;
КонецФункции
Разберем по шагам, что здесь происходит. Мы вызываем функцию ПолучитьКоличествоЧасовЗадачи, передавая в нее идентификатор. Внутри функции выполняется запрос, данные выгружаются в таблицу значений, рассчитывается итог по колонке, и этот итог возвращается обратно в вызывающую переменную КоличествоЧасов через оператор Возврат.
Что делать, если вам обязательно нужно использовать именно процедуру, или если из алгоритма требуется вернуть сразу несколько разных значений (например, общее количество часов, статус задачи и имя исполнителя)? В таком случае можно воспользоваться фундаментальной особенностью платформы 1С — передачей параметров по ссылке.
В 1С все параметры в процедуры и функции по умолчанию передаются по ссылке. Это означает, что переменная, переданная в процедуру в качестве аргумента, и переменная внутри самой процедуры указывают на одну и ту же область памяти. Если мы изменим значение этого параметра внутри процедуры, оно автоматически изменится и во внешнем коде, который эту процедуру вызвал.
Посмотрим на пример практической реализации данного подхода:
// Вызывающий код
ИД_Задачи = "12345";
КоличествоЧасов = 0; // Инициализируем переменную перед передачей
// Вызываем процедуру, передавая переменную КоличествоЧасов в качестве второго параметра
ПроверитьИДЗадачи(ИД_Задачи, КоличествоЧасов);
// Здесь переменная КоличествоЧасов уже содержит рассчитанное внутри процедуры значение
Сообщить("Количество часов: " + КоличествоЧасов);
// Описание процедуры
Процедура ПроверитьИДЗадачи(ИД, КоличествоЧасов)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КоличествоЧасовЗадачБитрикс.КоличествоЧасов КАК КоличествоЧасов
|ИЗ
| РегистрСведений.КоличествоЧасовЗадачБитрикс КАК КоличествоЧасовЗадачБитрикс
|ГДЕ
| КоличествоЧасовЗадачБитрикс.ID = &ИД";
Запрос.УстановитьПараметр("ИД", ИД);
РезультатЗапроса = Запрос.Выполнить();
Таб = РезультатЗапроса.Выгрузить();
// Присваиваем значение напрямую формальному параметру
КоличествоЧасов = Таб.Итог("КоличествоЧасов");
КонецПроцедуры
Этот способ отлично работает, однако он требует предварительной инициализации переменных в вызывающем коде. Если вы забудете объявить переменную перед вызовом процедуры, платформа может выдать ошибку или поведение программы станет непредсказуемым.
ЗначЧтобы глубже понимать логику работы платформы и избегать труднодоступных ошибок при передаче переменных, проанализируем поведение ключевого слова Знач (передача параметра по значению).
Если при объявлении процедуры перед именем параметра написать ключевое слово Знач, платформа создаст локальную копию переданного значения. Любые манипуляции с этой переменной внутри процедуры никак не повлияют на внешнюю переменную.
Особое внимание следует уделить поведению сложных объектов (коллекций данных, таких как Структура, Массив, ТаблицаЗначений, Соответствие):
Знач, внутри процедуры вы сможете полностью переопределить этот объект. Например, написав Параметр = Новый Структура;, вы очистите и внешнюю переменную тоже.Знач, платформа передаст так называемую «поверхностную копию» (копию ссылки на объект). В этом случае переопределить сам объект изнутри процедуры (написать Параметр = Новый Структура;) не получится — внешняя переменная останется нетронутой. Но! Вы по-прежнему сможете изменять свойства этой структуры внутри процедуры (например, Параметр.Вставить("НовоеСвойство", Значение);), и эти изменения будут видны снаружи.Когда мы разрабатываем управляемое приложение, крайне важно учитывать, где выполняется код — на клиенте или на сервере. При вызове серверной процедуры с клиента происходит сериализация данных (перевод объектов в формат XML/JSON) и передача их по сети.
Если вы передаете параметры в серверную процедуру без ключевого слова Знач, платформа 1С вынуждена выполнить двойную работу:
Даже если внутри серверной процедуры вы никак не меняли переданную таблицу значений или массив, платформа все равно вернет их обратно на клиент по сети, что создает колоссальную нагрузку на каналы связи и снижает скорость работы интерфейса.
Золотое правило оптимизации 1С: Всегда используйте ключевое слово Знач для всех параметров процедур и функций, передаваемых с клиента на сервер, если вам не требуется возвращать измененные значения обратно на клиент.
Для создания чистого, легко поддерживаемого кода фирма 1С рекомендует придерживаться следующих правил:
Структура. Например, создайте структуру ПараметрыЗаполнения, передайте ее в процедуру, заполните нужные ключи и анализируйте результат после вызова. Это делает код аккуратным и понятным.Использование функций вместо процедур дает разработчику мощные преимущества при решении сложных технических задач:
ОбщегоНазначения.ПолучитьПредставлениеСубъекта(Автор)). Использовать процедуры в схемах компоновки данных технически невозможно.Подводя итог, для возврата одного значения из алгоритма всегда используйте функции с оператором Возврат — это наиболее прозрачный, надежный и соответствующий стандартам 1С путь разработки. Если же вам необходимо спроектировать сложный заполняемый объект или вернуть множество разнородных данных, применяйте передачу параметров по ссылке через структуру.