Как проверить существование функции или процедуры в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

При разработке и сопровождении решений на платформе 1С нам часто приходится сталкиваться с необходимостью адаптации кода к различным версиям конфигураций или информационных баз. Одной из таких задач является динамическая проверка существования конкретной функции или процедуры, чтобы обеспечить корректную работу программы независимо от доступного функционала. Например, в новых версиях конфигурации могли появиться новые функции, а старые – быть удалены или переименованы. В этой статье мы подробно рассмотрим, как программно проверить существование функции или процедуры в 1С, основываясь на рекомендациях опытных разработчиков и возможностях платформы.

Использование конструкции "Попытка...Исключение"

Наиболее универсальным и надежным способом проверки существования функции или процедуры в 1С является применение конструкции "Попытка...Исключение". Этот подход позволяет безопасно попытаться вызвать потенциально несуществующую функцию, а в случае возникновения ошибки (например, "Метод объекта не обнаружен") перехватить ее и выполнить альтернативный код. Мы используем этот механизм, когда нам необходимо адаптировать наш код к различным версиям конфигураций, где функционал мог быть изменен, переименован или удален.

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

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


&НаСервереБезКонтекста Функция СформироватьШтрихкодEAN13()

    Попытка
        // Пытаемся вызвать новую функцию, предполагая, что она существует
        Возврат ПодключаемоеОборудованиеРТВызовСервера.СформироватьШтрихкод(); 
    Исключение
        // Если новая функция не найдена или возникла другая ошибка,
        // вызываем старую функцию
        Возврат ПодключаемоеОборудованиеРТ.СформироватьШтрихкод();
    КонецПопытки;

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

В данном примере мы сначала пытаемся вызвать функцию ПодключаемоеОборудованиеРТВызовСервера.СформироватьШтрихкод(), которая предположительно является новой версией или предназначена для определенного контекста. Если этот вызов завершается ошибкой (например, метод не найден, поскольку мы находимся в старой конфигурации или недоступном контексте), система переходит в блок Исключение. В этом блоке мы выполняем альтернативный вызов – функции ПодключаемоеОборудованиеРТ.СформироватьШтрихкод(), которая, по нашей логике, должна существовать в старой версии или другом контексте.

Преимущества этого метода:

  1. Надежность: Работает всегда, независимо от того, как сильно изменился внутренний код 1С или где именно находится функция.
  2. Гибкость: Позволяет обрабатывать не только отсутствие функции, но и другие ошибки, которые могут возникнуть при ее вызове.
  3. Простота реализации: Код легко читаем и понятен, не требует сложной логики.
  4. Устойчивость к изменениям: Нам не нужно заранее знать, какие функции появятся или исчезнут в будущих версиях; достаточно просто попытаться вызвать нужную и обработать возможное исключение.

Важно отметить, что при использовании Попытка...Исключение для проверки наличия функций, мы должны быть уверены, что исключение, которое мы перехватываем, действительно связано с отсутствием метода, а не с какой-либо другой логической ошибкой в самой функции. В большинстве случаев, когда проблема именно в отсутствии функции, платформа 1С генерирует ошибку типа "Метод объекта не обнаружен". В сложных сценариях можно дополнительно анализировать текст ошибки, хотя это и считается менее надежным подходом, так как текст ошибки может меняться между версиями платформы.

Проверка версии конфигурации

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

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

Для получения текущей версии конфигурации мы используем свойство Метаданные.Версия. Оно возвращает строковое представление версии, которое мы можем затем анализировать.

Рассмотрим пример:


// Предположим, что новая функция появилась начиная с версии 3.1.20.123
ТекущаяВерсияКонфигурации = Метаданные.Версия;

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

Если ТекущаяВерсияКонфигурации >= "3.1.20" Тогда // Пример строкового сравнения
    // Если текущая версия равна или больше 3.1.20, вызываем новую функцию
    Результат = ПодключаемоеОборудованиеРТВызовСервера.СформироватьШтрихкод();
Иначе
    // В противном случае (старая версия), вызываем старую функцию
    Результат = ПодключаемоеОборудованиеРТ.СформироватьШтрихкод();
КонецЕсли;

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

Важные моменты при использовании этого подхода:

  1. Точное знание изменений: Мы должны быть абсолютно уверены, с какой именно версии появился или изменился требуемый функционал. Это требует хорошего знания истории изменений конфигурации или документации к ней.
  2. Формат версии: Сравнение строк версий может быть нетривиальным, если формат версии не соблюдается строго (например, "3.1.9" и "3.1.10" как строки, а не числа). Для более надежного сравнения необходимо учитывать, что строковое сравнение может дать некорректный результат (например, "3.1.10" < "3.1.9"). В типовых конфигурациях на БСП часто есть общие функции для сравнения версий, например, в модулях типа "ОбщегоНазначенияБСП" или "ВерсионированиеОбъектовКлиентСервер", которые умеют правильно работать с многокомпонентными номерами версий. Если такой функции нет, нам придется парсить строку версии на числовые компоненты и сравнивать их по отдельности.
  3. Меньшая гибкость: Если функция исчезнет в будущей версии или будет переименована, нам придется обновлять код проверки версии. Попытка...Исключение в этом плане более устойчива к непредвиденным изменениям, так как она реагирует на факт отсутствия, а не на заранее известное условие.

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

Проверка наличия общего модуля

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

Для этого мы используем коллекцию метаданных Метаданные.ОбщиеМодули и метод Найти():


ИмяМодуляДляПроверки = "ПодключаемоеОборудованиеРТВызовСервера"; // Имя общего модуля, который мы хотим проверить

Если Метаданные.ОбщиеМодули.Найти(ИмяМодуляДляПроверки) <> Неопределено Тогда
    // Общий модуль с таким именем найден в конфигурации.
    // Теперь мы можем попытаться вызвать функцию из него,
    // используя Попытка...Исключение для полной надежности.
    Попытка
        Результат = ПодключаемоеОборудованиеРТВызовСервера.СформироватьШтрихкод();
    Исключение
        // Если модуль существует, но функция внутри него все же отсутствует
        // или произошла другая ошибка при вызове, переходим к альтернативе.
        Результат = ПодключаемоеОборудованиеРТ.СформироватьШтрихкод();
    КонецПопытки;
Иначе
    // Общий модуль с таким именем не найден в конфигурации.
    // Сразу вызываем старую функцию или обрабатываем ситуацию иным способом,
    // так как вызов функции из несуществующего модуля приведет к критической ошибке.
    Результат = ПодключаемоеОборудованиеРТ.СформироватьШтрихкод();
КонецЕсли;

Мы видим, что даже после проверки наличия модуля, для гарантии вызова конкретной функции внутри него, нам все равно приходится прибегать к Попытка...Исключение. Это связано с тем, что наличие модуля не гарантирует наличия конкретной экспортной процедуры или функции внутри него. Таким образом, проверка наличия модуля является лишь вспомогательным шагом и не заменяет основной механизм обработки ошибок при вызове отсутствующего метода. Она может быть полезна для оптимизации, чтобы избежать попытки вызова функции из модуля, который точно отсутствует, до того, как мы дойдем до блока Попытка...Исключение.

Ограничения функции "ОбщегоНазначения.ПроверитьИмяПроцедурыКонфигурации"

В ходе обсуждения на форуме была упомянута функция ОбщегоНазначения.ПроверитьИмяПроцедурыКонфигурации. Нам важно понимать, что эта функция, хотя и существует в конфигурациях на основе БСП (Библиотеки стандартных подсистем), имеет очень ограниченное применение и не предназначена для проверки реального существования функции или процедуры в конфигурации, доступной для вызова из прикладного кода.

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

  1. Реальное наличие процедуры с таким именем в каком-либо модуле конфигурации.
  2. Является ли эта процедура экспортной и доступна ли она для вызова извне модуля, где она определена.
  3. Наличие процедуры в текущем контексте выполнения (например, на клиенте или на сервере, в зависимости от атрибутов).

Кроме того, сама функция ОбщегоНазначения.ПроверитьИмяПроцедурыКонфигурации, как правило, не является экспортной. Это означает, что ее нельзя вызвать из произвольного модуля конфигурации или внешнего отчета/обработки без специальных ухищрений (например, вызова через серверные вызовы, если она сама не находится в клиентском контексте, или создания собственной экспортной обертки). Это еще раз подчеркивает, что она не предназначена для широкого использования в прикладном коде для динамической проверки наличия функций.

Таким образом, мы не рекомендуем полагаться на эту функцию для решения задачи, поставленной в начале темы – динамической проверки существования и доступности функций для вызова. Для этих целей следует использовать более надежные методы, такие как Попытка...Исключение или проверка версии конфигурации, которые оперируют фактом возможности вызова, а не только синтаксической корректностью имени.

Заключение

Мы проанализировали несколько подходов к проверке существования функций и процедур в 1С, каждый из которых имеет свои преимущества и области применения. Наиболее универсальным и рекомендуемым является использование конструкции "Попытка...Исключение", которая обеспечивает надежную обработку ситуации, когда вызываемый метод отсутствует. Этот подход позволяет нам создавать устойчивый к изменениям код, который будет корректно работать в различных версиях конфигураций, минимизируя риск критических ошибок.

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

Мы также выяснили, что проверка наличия общего модуля через Метаданные.ОбщиеМодули.Найти() может быть вспомогательной, но не заменяет необходимость обработки ошибок вызова самой функции, поскольку модуль может существовать, но требуемая функция внутри него – нет. А функция ОбщегоНазначения.ПроверитьИмяПроцедурыКонфигурации, несмотря на свое название, не предназначена для проверки реального существования и доступности методов, выполняя лишь форматный контроль имени.

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

← На главную