头图

笔者之前的文章被很多人误解的 ABAP 关键字:READ-ONLY 发布之后,有朋友询问,SAP 标准实现里,对这个 READ-ONLY 使用的场景多吗?

其实这个问题我们可以自己找到答案。

思路是选择一个 SAP 系统,统计出类的总数,这些类总共定义了多少个属性,其中有多少属性,使用了 READ-ONLY 来修饰。

首先打开 SE80 的 Repository Information System,这里仅能通过类属性的名称进行统计。

但我们的需求是,根据类公有属性经过 READ-ONLY 修饰与否来统计,所以这条路走不通。

下图展示了 SE80 中的 Repository Information System,仅能通过类属性的名称进行查询。

那么还是直接找表吧。类属性的名称和 READ-ONLY 标志位,肯定是存储在后台某张数据库表里的。

笔者本公众号过去大量的文章,通过很多例子,反复介绍了如何自行查找存储了指定信息的数据库表。

通过文章里介绍的技巧,我们找到了数据库表 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

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 和修改保护的知识点,能够帮助大家弥补上相关的知识漏洞,感谢阅读。


注销
1k 声望1.6k 粉丝

invalid