每个 ABAP 程序都以一个程序启动语句开始,该语句取决于程序类型。
在程序启动语句之后,每个程序都包含一个全局声明部分,您可以在其中实现在整个程序中有效且可见的定义和声明。这包括数据类型和数据对象的声明,以及 ABAP 对象中接口的定义或类的声明部分。
接口和类的定义包含其组件的声明。虽然各个定义和声明的顺序不是固定的,但您必须考虑到 ABAP 语句只能引用已经建立的定义和声明。例如,引用变量只能引用先前定义的类,而该类又只能实现先前定义的接口。引入过程后,您可以声明该过程中可见的数据类型和数据对象。从最广泛的意义上讲,数据类型的声明还包括在编写程序时数据类型未确定的对象的类型。
ABAP 程序的功能是在处理块中实现的,这些处理块列在全局声明部分下。处理块是用模块化语句定义的。您可以在过程类型处理块中使用声明性语句来定义本地数据类型和数据对象。其他处理块没有本地数据区域,任何声明性语句都适用于全局程序。方法是 ABAP 对象中最重要的处理块。它们只能在其类的实现部分中实现。处理块和/或实现部分的顺序与程序执行无关,但应设计成使程序易于阅读。
ABAP 程序的所有其他语句都是实现语句,它们始终属于处理块。您可以使用实现语句来实现处理块的功能。所有类型的处理块的功能主要是使用相同的语句来实现的。
程序编辑
除了 ABAP Workbench 中的静态程序开发之外,您还可以使用语言元素编辑和生成 ABAP 程序的组件、源代码、文本元素和屏幕。这种类型的程序开发称为动态程序开发。
动态程序开发的语句提供了一种强大而灵活的动态编程方法,但这种编程方式非常复杂,并且创建的程序难以维护。因此,建议您在使用动态程序开发之前首先使用应用程序的其他动态编程选项。
动态程序开发的语句不进行授权检查或其他检查。相反,这些必须手动编程。除了 AUTHORITY-CHECK
语句之外,您还可以使用以下特殊功能模块来进行所需的检查。
- 功能模块
RS_ACCESS_PERMISSION
执行所有授权检查,这些检查也在调用 ABAP 编辑器时执行。 - 功能模块
TR_SYS_PARAMS
和功能组STR9
的其他功能模块决定 Repository 对象的可更改性。
动态子程序池 GENERATE SUBROUTINE POOL
语法:
css
GENERATE SUBROUTINE POOL itab NAME prog [error_handling].
该语句生成一个临时子程序池。子程序池的源代码取自内表 itab
。生成的子程序池内部存储在当前内部会话中。临时子例程池的 8 个字符名称分配给变量 prog
。
可以为 prog 指定以下内容:
- 现有的字符型变量
- 内部声明
DATA(var)
, 其中声明了一个 PROGNAME 类型的变量
itab
只允许不带二级表 Key 的标准表。 itab
的行类型必须是字符类型。 itab
中的一行源代码不能超过 255 个字符(如果行类型有固定长度,则尾部空白将会忽略)。数据对象 prog
也必须是字符类型。在一个内部会话中,最多可以创建 36 个临时子程序池。
如果 itab
中的源代码有语法错误,则不会使用 prog
生成和初始化子程序池。新增的 error_handling 可用于分析语法错误和生成错误。在语法检查中,Switch Framework 的开关配置将使用当前事务被调用时的状态。
如果在生成子程序池时出现异常,运行时错误将在内部处理,因此不会终止程序。相反,sy-subrc
会被设置为值 8。不过,数据库仍会回滚,相应的短转储也会正常保存。添加的 SHORTDUMP-ID 可用于确定运行时错误的 ID。
在子程序池的源代码中,通过使用语句 PERFORM
指定程序名 prog
,可以从同一内部会话中加载的所有程序中调用子程序。当首次调用子程序池中的子程序时,该子程序将被加载到内部会话中,并触发事件 LOAD-OF-PROGRAM
。

- 因为子例程作为程序模块化的方法现在已经过时,所以使用
GENERATE SUBROUTINE POOL
创建的临时子例程池应该只包含一个调用本地类方法的起始子例程,并且不包含任何其他功能编码。随后显示的示例表明您也可以完全不使用子例程。 - 内表
itab
中的源代码必须包含完整的ABAP程序,包括程序启动语句。 - 可以像存储库的静态子例程池中一样定义相同的全局声明和处理块。
- 添加介绍性
PROGRAM
语句的REDUCED FUNCTIONALITY
也适用于临时子例程池,建议减少其资源使用。 - 无法显式删除为内部会话生成的临时子例程池。从其生成到整个内部会话终止,它都保持可用。
测试
动态创建和生成实现本地类的子例程池。可以使用类的绝对类型名来调用类的静态方法 meth
。
ABAP
DATA itab TYPE TABLE OF string.
DATA prog TYPE string.
DATA class TYPE string.
APPEND `program.` TO itab.
APPEND `class main definition.` TO itab.
APPEND ` public section.` TO itab.
APPEND ` class-methods meth.` TO itab.
APPEND `endclass.` TO itab.
APPEND `class main implementation.` TO itab.
APPEND ` method meth.` TO itab.
APPEND ` message 'Test' type 'I'.` TO itab.
APPEND ` endmethod.` TO itab.
APPEND `endclass.` TO itab.
GENERATE SUBROUTINE POOL itab NAME prog.
class = `\PROGRAM=` && prog && `\CLASS=MAIN`.
CALL METHOD (class)=>meth.
这个例子通过动态创建子例程,然后调用类方法 CALL METHOD (class)=>meth.
,输出结果:

同理,也能够动态创建和生成本地类的子例程池。然后将类实例化,并动态调用实例方法 meth
,输出相同的结果:
ABAP
DATA itab TYPE TABLE OF string.
DATA prog TYPE string.
DATA class TYPE string.
DATA oref TYPE REF TO object.
APPEND `program.` TO itab.
APPEND `class main definition.` TO itab.
APPEND ` public section.` TO itab.
APPEND ` methods meth.` TO itab.
APPEND `endclass.` TO itab.
APPEND `class main implementation.` TO itab.
APPEND ` method meth.` TO itab.
APPEND ` message 'Test' type 'I'.` TO itab.
APPEND ` endmethod.` TO itab.
APPEND `endclass.` TO itab.
GENERATE SUBROUTINE POOL itab NAME prog.
class = `\PROGRAM=` && prog && `\CLASS=MAIN`.
CREATE OBJECT oref TYPE (class).
CALL METHOD oref->('METH').
官方更复杂的 SQL 语句和子程序也能用在内表结构中,创建并生成(动态)一个子程序池,以实现事件块 LOAD-OF-PROGRAM
和两个子程序。根据返回代码 sy-subrc
,将调用一个子程序或发出一条消息。:
ABAP
DATA tab TYPE STANDARD TABLE OF string WITH EMPTY KEY.
tab = VALUE #(
( `PROGRAM subpool.` )
( `DATA spfli_tab TYPE TABLE OF spfli.` )
( `LOAD-OF-PROGRAM.` )
( ` SELECT *` &
` FROM spfli` &
` INTO TABLE @spfli_tab.` )
( `FORM loop_at_tab.` )
( ` DATA spfli_wa TYPE spfli.` )
( ` LOOP AT spfli_tab INTO spfli_wa.` )
( ` PERFORM evaluate_wa USING spfli_wa.` )
( ` ENDLOOP.` )
( `ENDFORM.` )
( `FORM evaluate_wa USING l_wa TYPE spfli.` )
( ` cl_demo_output=>write_data( l_wa ).` )
( `ENDFORM.` ) ).
GENERATE SUBROUTINE POOL tab NAME DATA(prog)
MESSAGE DATA(mess)
SHORTDUMP-ID DATA(sid).
IF sy-subrc = 0.
PERFORM ('LOOP_AT_TAB') IN PROGRAM (prog) IF FOUND.
cl_demo_output=>display( ).
ELSEIF sy-subrc = 4.
MESSAGE mess TYPE 'I'.
ELSEIF sy-subrc = 8.
MESSAGE sid TYPE 'I'.
ENDIF.
总结
可能在日常开发中,我们会很少用 Generate Subroutine Pool
作为程序内容,但是如果让你开发一个动态程序,需要实现不同数据库后台表的查询功能。那么就可以使用 Generate Subroutine Pool
。
如果使用得当,生成子例程池是一个非常强大的语法。
参考链接: