笔者之前的文章被很多人误解的 ABAP 关键字:READ-ONLY 发布之后,有朋友询问,SAP 标准实现里,对这个 READ-ONLY 使用的场景多吗?
其实这个问题我们可以自己找到答案。
思路是选择一个 SAP 系统,统计出类的总数,这些类总共定义了多少个属性,其中有多少属性,使用了 READ-ONLY 来修饰。
首先打开 SE80 的 Repository Information System,这里仅能通过类属性的名称进行统计。
但我们的需求是,根据类公有属性经过 READ-ONLY 修饰与否来统计,所以这条路走不通。
下图展示了 SE80 中的 Repository Information System,仅能通过类属性的名称进行查询。
那么还是直接找表吧。类属性的名称和 READ-ONLY 标志位,肯定是存储在后台某张数据库表里的。
笔者本公众号过去大量的文章,通过很多例子,反复介绍了如何自行查找存储了指定信息的数据库表。
- SAP错误消息调试之七种武器:让所有的错误消息都能被定位
- 授人以渔:如何找到 ABAP 主程序和 Include 程序关联关系的存储表
- 一套适合 ABAP 初级和中级开发人员,从入门到提高的 ABAP 学习教程
通过文章里介绍的技巧,我们找到了数据库表 SEOCOMPODF.
这张表的 CLSNAME,CMPNAME 和 ATTRDONLY 字段,分别存储了类的名称,类属性的名称,以及类属性是否被 READ-ONLY 修饰的状态信息。
笔者的 SAP CRM 系统上,总共有 260 万个类属性(包含 SAP 标准实现和 Z 实现)。
其中 READ-ONLY 属性有 9 万 5 千个,占总数的 3.6% 左右。
当然我们可以把统计范围再缩小一点:只统计 SAP 标准类里的 Public 属性,看其中到底有多少,启用了 READ-ONLY.
在类名称 CLSNAME 的选择条件里,将那些通过 Y 或者 Z 开头的类过滤掉。
Exposure 字段统计条件为 2,代表 Public 属性。
在笔者系统里,总共有 175 万个公有属性。
其中 9 万 4 千个公有属性被 READ-ONLY 修饰,占总数 5.4% 左右。
这个统计数据充分说明,SAP 自身也是严格按照 Clean ABAP 编程规范里的规则,慎用 READ-ONLY 来进行开发的。
SAP 建议慎用 READ-ONLY 的原因,在笔者前一篇文章已经详细论述过,本文不再赘述。
ABAP 和类公有属性的 READ-ONLY 相关的,还有另一个概念:修改保护(Change protection),有时也称写保护(Write Protection).
通过实际的例子来介绍修改保护的概念。
下面的代码可以通过编译,但是执行时,会遇到运行时错误:
MOVE_TO_LIT_NOTALLOWED_NODATA
FORM read_only USING iv_i TYPE int4.
WRITE:/ iv_i.
iv_i = 2.
ENDFORM.
START-OF-SELECTION.
PERFORM read_only USING 1.
错误消息:
A new value is to be assigned to the field, although this field is entirely or partly protected against changes.
大意是 subroutine 的输入参数 iv_i 是被修改保护的,而其实现体内的代码,试图对这个被保护的变量赋值,因此产生了运行时错误。
在 ABAP 调试器里,能清楚看到输入参数 iv_i,被标注了 Read Only 的 Checkbox.
Subroutine 已经是一种被废弃的语法,不推荐再使用。
那么我们把上述代码移植到 ABAP 类里面,结果又如何呢?
下面代码第 12 行,试图在类的方法里,修改输入参数的值:
REPORT zbook.
CLASS lcl_test DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: test IMPORTING iv_i TYPE int4.
ENDCLASS.
CLASS lcl_test IMPLEMENTATION.
METHOD: test.
WRITE:/ iv_i.
iv_i = 45.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
lcl_test=>test( iv_i = 4 ).
这段代码无法通过编译,遇到错误消息:
the field iv_i cannot be modified.
如果把上图第 12 行代码注释掉,就可以通过编译,成功激活代码。
在调试器里,可以看到输入参数的 READ-ONLY Flag 被勾上了。
看来面向对象的编程范式确实比 Subroutine 健壮很多,可以从语法检查层面规避很多问题。
如果给输入参数 iv_i 添加另一个 VALUE 关键字进行修饰,如下图图例 1 的位置所示,在运行时我们发现,该输入参数的 READ-ONLY 标志位,已经被清除了。
这样一来,在方法内部,可以对这个输入参数进行赋值了。
VALUE 关键字其实蕴含了另一个关于 ABAP 方法调用时,参数传递方式的知识点。
用 VALUE 关键字修饰输入参数,意思就是参数传递采取传值方式进行。
下图第 18 行的实际输入参数 lv_input,在调用 test 方法时,该参数的实际值 4,被传递进 test 方法内,拷贝给 test 的形式参数 iv_input.
因此在 test 方法内部,第 11 行的 iv_i = 45, 修改的是形式参数 iv_i 的值,从拷贝进来的 4 修改成 45,对实际参数 lv_input 没有任何影响,其值仍然为 4 不变。
而如果去掉 VALUE, 参数传递采取 ABAP 默认的引用传递,此时形式参数 iv_i 和实际输入参数 lv_input 具有同一个引用,而 ABAP 输入参数是具有修改保护的,因此在引用传递的前提下,方法内试图输入参数 iv_i 的值,会遇到上面提到的语法错误:the field iv_i cannot be modified.
ABAP 方法和函数调用的参数传递,默认都是引用传递。但是在 RFC 函数的参数声明里,必须使用值传递方式。
希望本文介绍的 READ-ONLY 和修改保护的知识点,能够帮助大家弥补上相关的知识漏洞,感谢阅读。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。