В процессе разработки в среде «1С:Предприятие 8» (особенно при создании универсальных отчетов, обработок или динамических механизмов интеграции) перед программистом нередко возникает задача: выполнить произвольную строку текста как реальный программный код. Например, когда в переменной хранится строка вида "Число(10.05)" или "Справочники.Номенклатура.НайтиПоРеквизиту(...)", и нам необходимо получить результат вычисления этой строки.
В этой статье мы подробно разберем, как правильно решать подобные задачи, проанализируем разницу между встроенными механизмами платформы, рассмотрим контекстные ограничения управляемых форм и научимся писать безопасный и производительный код.
Для динамического исполнения кода платформа 1С предлагает два основных инструмента. Начинающие разработчики часто путают их, что приводит к синтаксическим ошибкам на этапе выполнения. Давайте разберем принципиальное различие между ними.
Функция Вычислить(<СтрокаВыражения>) предназначена исключительно для вычисления математических, логических или объектных выражений, которые возвращают конкретное значение. Ее можно использовать непосредственно в правой части оператора присваивания.
Рассмотрим простой пример, аналогичный вопросу автора темы:
ТекСтрока = "Число(10.05)";
// Функция выполнит преобразование и вернет числовое значение
НовЧисло = Вычислить(ТекСтрока);
В результате переменная НовЧисло примет тип Число со значением 10.05.
Важное синтаксическое ограничение: строка, передаваемая в функцию Вычислить(), должна содержать только одно выражение и не должна оканчиваться точкой с запятой (символом ;). Например, вызов Вычислить("2 + 2;") вызовет критическую ошибку выполнения, тогда как Вычислить("2 + 2") отработает корректно.
Оператор Выполнить(<СтрокаКода>) представляет собой процедуру. Он просто выполняет переданный ему фрагмент кода (инструкцию, цикл, условие) и не возвращает значения напрямую. Попытка написать Результат = Выполнить(...) вызовет ошибку компиляции.
Чтобы получить результат работы оператора Выполнить(), нам необходимо заранее объявить переменную в текущем контексте модуля и переопределить ее значение внутри исполняемой строки. Давайте посмотрим на пример:
// 1. Объявляем переменную в текущем контексте
РезультатВычисления = Неопределено;
// 2. Формируем строку кода, которая присваивает значение нашей переменной
СтрокаКода = "РезультатВычисления = Число(10.05);";
// 3. Выполняем код
Выполнить(СтрокаКода);
// Переменная РезультатВычисления теперь хранит число 10.05
Внутри строки для Выполнить() можно писать сложные многострочные конструкции с условиями и циклами, однако там нельзя объявлять новые локальные процедуры, функции или использовать ключевое слово Перем.
Поскольку современная разработка в 1С базируется на управляемом приложении, критически важно помнить о контекстных ограничениях.
Методы Вычислить() и Выполнить() недоступны на Тонком и Веб-клиенте. Попытка вызвать их непосредственно в клиентской процедуре (под директивой &НаКлиенте) приведет к ошибке компиляции «Процедура или функция с указанным именем не определена».
Для решения этой проблемы выполнение динамического кода всегда должно переноситься на сторону сервера. Давайте проанализируем правильный шаблон реализации для Управляемой Формы:
&НаКлиенте
Процедура ВыполнитьКодНаКлиенте(Команда)
СтрокаВыражения = "Число(10.05)";
// Вызываем серверную функцию для безопасного вычисления
Результат = ПолучитьЗначениеНаСервере(СтрокаВыражения);
ПоказатьПредупреждение(, "Результат: " + Результат);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьЗначениеНаСервере(СтрокаВыражения)
// На сервере функция Вычислить() работает без ограничений
Возврат Вычислить(СтрокаВыражения);
КонецФункции
В сообщении №7 автор темы пытается решить задачу динамического поиска элемента справочника по коду:
ГдеСпр = "Справочники.Контрагенты.НайтиПоКоду(" + Код + ")";
Использование Выполнить() или Вычислить() для динамического обращения к объектам метаданных (справочникам, документам, регистрам) считается плохой практикой разработки (anti-pattern). Такой код сложно отлаживать, он работает медленнее и подвержен ошибкам при изменении структуры метаданных.
Платформа 1С:Предприятие 8 предоставляет великолепную встроенную альтернативу — обращение к коллекциям метаданных через квадратные скобки [] по имени объекта. Давайте разберем, как сделать это правильно, красиво и быстро:
// Вместо генерации сложной строки кода:
ИмяСправочника = "Контрагенты";
ИскомыйКод = "000000001";
// Обращаемся к менеджеру справочника динамически по имени
СсылкаНаОбъект = Справочники[ИмяСправочника].НайтиПоКоду(ИскомыйКод);
Если СсылкаНаОбъект.Пустая() Тогда
Сообщить("Элемент не найден!");
Иначе
Сообщить("Успешно найдено: " + СсылкаНаОбъект);
КонецЕсли;
Этот подход обладает следующими преимуществами:
Если специфика вашей задачи всё же требует выполнения произвольного текста (например, вы пишете консоль кода или сложный загрузчик данных), необходимо помнить об информационной безопасности. Выполнение неконтролируемого текста, введенного пользователем, аналогично уязвимости SQL-инъекций. Злоумышленник может передать деструктивный код, который повредит базу данных или получит доступ к конфиденциальным файлам на сервере.
Для минимизации рисков придерживайтесь следующих правил:
УстановитьБезопасныйРежим(Истина);
Выполнить(СтрокаКода);
УстановитьБезопасныйРежим(Ложь);
ОбщегоНазначения:
ОбщегоНазначения.ВычислитьВБезопасномРежиме()ОбщегоНазначения.ВыполнитьВБезопасномРежиме()Применяя данные подходы, вы сможете создавать гибкие решения в среде 1С, сохраняя при этом высокую производительность, стабильность и безопасность вашей информационной системы.