Процедуры ABL
Файл процедуры ABL представляет собой текстовый файл с расширением .p , который содержит исходный код процедур приложения. Сам файл известен как внешняя процедура, но он может содержать в себе другие процедуры, называемые внутренними процедурами. В этом разделе содержится информация, относящаяся к процедурам ABL.
- Внешние и внутренние процедуры
- Выполнение процедуры
- Возврат значения из процедуры
- Использование параметров в процедуре
- Постоянные (персистентные) процедуры
- Организация файлов процедур
Внешние и внутренние процедуры
Файл процедуры ABL ( .p ) называется внешняя процедура. Он может принимать параметры или возвращать строковое значение. В следующем примере кода показана внешняя процедура helloworld.p:
/* helloworld.p */ MESSAGE "Hello World".
Внутренняя процедура ABL — это ещё один тип процедуры, который определяется именованными точками входа в файле внешней процедуры. Вы определяете начало внутренней процедуры с помощью оператора PROCEDURE и указываете конец процедуры с помощью оператора END. В одном и том же файле внешней процедуры может быть много внутренних процедур. В следующем примере кода есть две внутренние процедуры с именем proc1 и proc2 во внешнем файле процедур, myprocedures.p .
/* myprocedures.p */ PROCEDURE proc1: /* ABL code */ MESSAGE "In proc1". END PROCEDURE. PROCEDURE proc2: /* ABL code */ MESSAGE "In proc2". END PROCEDURE. RUN proc1. RUN proc2.
Область действия переменных для внутренних процедур
Вы можете определить переменные на глобальном уровне в основном блоке, которые также могут использоваться внутренними процедурами, определенными в том же файле. Однако переменные, определенные во внутренней процедуре, могут использоваться только во внутренней процедуре.
Выполнение процедуры
Когда вы выполняете внешний файл процедуры, такой как helloworld.p , вы включаете расширение .p в имя процедуры. Внутренние процедуры выполняются почти так же, как и внешние процедуры, за исключением того, что у имени внутренней процедуры нет расширения имени файла. В следующем примере кода показано выполнение как внешней, так и внутренней процедуры:
/* myprocedures.p */ PROCEDURE proc1: /* ABL code */ MESSAGE "In proc1". END PROCEDURE. PROCEDURE proc2: /* ABL code */ MESSAGE "In proc2". END PROCEDURE. RUN helloworld.p. // run external procedure RUN proc1. // run internal procedure
Дополнительные сведения см. в разделе “Выполнение процедур ABL” руководства «Разработка приложений ABL».
Возврат значения из процедуры
Вы можете использовать оператор RETURN, чтобы вернуть выполнение вызывающей стороне, опционально указав возвращаемое строковое значение. (Обратите внимание на то, что, если вы хотите вернуть значение, отличное от строки, вам нужно использовать функцию, а не процедуру.) В вызывающей программе для получения возвращаемого значения используется функция RETURN-VALUE. Допускается использование нескольких операторов RETURN в рамках одной процедуры. В следующем примере кода показано, как возвращаемое значение устанавливается в процедуре proc1, а затем возвращённое значение извлекается в вызывающей процедуре:
/* myprocedures.p */ PROCEDURE proc1: /* ABL code */ MESSAGE "In proc1". RETURN "1". END PROCEDURE. PROCEDURE proc2: /* ABL code */ MESSAGE "In proc2". END PROCEDURE. RUN proc1. MESSAGE "The return value from proc1 is" RETURN-VALUE.
Для получения дополнительной информации см. “Операторы RETURN и RETURN-VALUE” руководства «Разработка приложений ABL».
Использование параметров в процедуре
Для передачи значений в процедуру или из неё определяются параметры с помощью оператора DEFINE PARAMETER. Определение параметра присваивает имя параметру, указывает, получает ли он ввод или обеспечивает вывод, или и то, и другое, а также указывает тип данных. Упрощённый синтаксис оператора DEFINE PARAMETER:
DEFINE { INPUT | OUTPUT | INPUT-OUTPUT } PARAMETER parameter-name AS datatype [ NO-UNDO ] [ INITIAL initial-value ]
INPUT | OUTPUT | INPUT-OUTPUT
INPUT – значение передаётся выполняемой процедуре.
OUTPUT – значение возвращается вызывающей стороне после завершения вызванной процедуры.
INPUT-OUTPUT – значение передаётся в процедуру, которая может изменить переданное значение. AVM передаёт значение обратно вызывающей стороне, когда процедура завершается.
parameter-name
Имя параметра.
datatype
Тип данных параметра. Вы можете использовать любой из стандартных типов данных ABL, включая CHARACTER, INTEGER, DECIMAL, LOGICAL, DATE. Вы также можете указать TABLE, DATASET, TABLE-HANDLE или DATASET-HANDLE, но они используют немного другой синтаксис.
initial-value
Начальное значение параметра. Это относится только к OUTPUT параметрам.
Параметры передаются из вызывающей процедуры в вызываемую процедуру оператором RUN. Когда вы указываете параметр, вы также указываете тип используемого параметра ( INPUT, OUTPUT, или INPUT-OUTPUT). Тип INPUT используется по умолчанию, но рекомендуется указать тип параметра, чтобы ваш код был недвусмысленным для других разработчиков.
Вы должны убедиться, что при вызове процедуры, которая принимает параметры, количество и порядок параметров совпадают, а также их типы данных ABL и типы ввода/вывода. В вызывающей процедуре, когда вы используете переменные для передачи значений в процедуру и из неё, имена переменных могут не совпадать с именами, используемыми в процедуре.
Дополнительные сведения см. в разделах “Синтаксис определения параметров” и “Синтаксис передачи параметров” в «Справочном руководстве по ABL».
Следующий пример кода демонстрирует передачу параметров:
VAR CHAR v1 = "XXX". VAR CHAR v2 = "YYY". VAR CHAR v3 = "ZZZ". /* proc2 */ PROCEDURE proc2: DEFINE INPUT PARAMETER p1 AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER p2 AS CHARACTER NO-UNDO. DEFINE INPUT-OUTPUT PARAMETER p3 AS CHARACTER NO-UNDO. p1 = "XXXXXX". p2 = "YYYYYY". p3 = "ZZZZZZ". MESSAGE "In proc2: p1, p2, p3:" p1 p2 p3. END PROCEDURE. /* main */ MESSAGE "Before running proc2: v1, v2, v3:" v1 v2 v3. RUN proc2 (INPUT v1, OUTPUT v2, INPUT-OUTPUT v3). MESSAGE "After running proc2: v1, v2, v3:" v1 v2 v3.
Результат выполнения кода:
Before running proc2: v1, v2, v3: XXX YYY ZZZ In proc2: p1, p2, p3: XXXXXX YYYYYY ZZZZZZ After running proc2: v1, v2, v3: XXX YYYYYY ZZZZZZ
Постоянные (персистентные) процедуры
Постоянная процедура — это экземпляр процедуры, который остаётся резидентным в памяти AVM до тех пор, пока он не будет явно удалён. Вы можете использовать постоянные процедуры как «кэш памяти» для часто используемых процедур и функций. Процедура сохраняет своё состояние. Например, если вызываемая вами внутренняя процедура устанавливает переменную на уровне .p (главного блока), то это значение остаётся установленным и может затем использоваться из другой внутренней процедуры.
Поскольку процедура остаётся в памяти, AVM не нужно загружать программу в память каждый раз, когда она вызывается. Таким образом, ваше приложение получает преимущество в производительности.
Чтобы создать экземпляр постоянной процедуры в памяти, используется оператор RUN с ключевым словом PERSISTENT. Вы также должны определить дескриптор процедуры, чтобы обращаться к ней позже.
Чтобы создать экземпляр постоянной процедуры, используйте следующий синтаксис:
RUN proc-name PERSISTENT SET proc-handle-name.
В следующем примере кода мы определяем переменную дескриптора процедуры hEmpLibrary и создаём экземпляр постоянной процедуры, устанавливающей переменную дескриптора процедуры. Вы должны убедиться, что процедура, которую вы выполняете, находится в вашем PROPATH во время выполнения.
VAR HANDLE hEmpLibrary. RUN emplibrary.p PERSISTENT SET hEmpLibrary.
После создания экземпляра постоянной процедуры вы можете запустить любую из её внутренних процедур в библиотеке. Используйте дескриптор процедуры для ссылки на внутренние процедуры.
RUN proc-name IN proc-handle-name [ (parameter-list) ].
В следующем примере кода мы определяем переменную дескриптора процедуры hEmpLibrary и создаём экземпляр постоянной процедуры с помощью оператора RUN. В конструкции FOR EACH вызываем внутреннюю процедуру calcvacation для каждого сотрудника и отображаем информацию из полей записи.
/* eCheckEmpVacAvailable.p */ VAR DATE dtStart. VAR DATE dtEnd. VAR LOGICAL lOK. VAR HANDLE hEmpLibrary. RUN emplibrary.p PERSISTENT SET hEmpLibrary. FOR EACH Employee: lOK = FALSE. RUN calcvacation IN hEmpLibrary(INPUT EMPLOYEE.EMPNUM, INPUT dtStart, INPUT dtEnd, OUTPUT lOK). DISPLAY Employee.FirstName Employee.LastName lOK label "Vac?". END.
Организация файлов процедур
Существует несколько способов организации файлов процедур. Хорошей практикой является создание файлов процедур со связанными функциями (библиотеки), которые содержат только внутренние процедуры. После чего вы можете сделать эти библиотеки доступными для других частей вашего приложения. Это способствует повторному использованию и упрощает поддержку приложения.
Другой хорошей практикой является отделение логики пользовательского интерфейса (UI) от бизнес-логики. Логикой пользовательского интерфейса может быть мобильное или веб-приложение или настольный клиент ABL GUI. Отделение логики пользовательского интерфейса от бизнес-логики упрощает обновление приложения, поскольку, как правило, изменения в одной части приложения не влияют на другую сторону. В современном приложении логика пользовательского интерфейса не имеет прямого доступа к базе данных. Логика пользовательского интерфейса запрашивает данные из бизнес-логики, которая, в свою очередь, извлекает данные из базы данных. Обмен данными между логикой пользовательского интерфейса и бизнес-логикой осуществляется с использованием временных таблиц и наборов данных ABL.