본문 바로가기

SAP&ABAP

EASY ABAP - 6. Subroutine

728x90

 Subroutine은 Java의 메서드를 생각하면 된다. 형식은 FORM으로 시작해서 ENDFORM으로 끝난다.


PERFORM WRITE_DATA.

FORM WRITE_DATA.

  WRITE : / 'SUBROUTINE'.

ENDFORM.

 

Subroutine 파라미터

 서브루틴을 호출할 때 사용하는 파라미터를 Actual Parameter라 하고 서브루틴에서 사용되는 파라미터를 Formal Parameter라고 한다.

 파라미터를 3가지 유형으로 주고받을 수 있다.

- Call by Value : Actual Parameter와 Formal Parameter가 물리적으로 다른 메모리 영역을 갖는다.

- Call by Reference : 물리적으로 같은 메모리 영역을 공유하여 넘겨준다. 즉, 주소값을 넘겨주는 것

- Call by Value and Result : 변수의 값을 넘겨주고 받는 구문에서 작업을 성공적으로 수행하였을 경우 변경된 값을 돌려준다. 물리적으로는 다른 영역을 사용한다.

 

Call by Value

- USING 키워드 다음에 파라미터를 사용하고 VALUE 구문으로 완성한다.

 

DATA : GV_VAL TYPE C LENGTH 30 VALUE 'CALL BY VALUE CHECK'.

PERFORM CALL_BYVALUE USING GV_VAL. " CALL BY VALUE로 수행

WRITE : / GV_VAL. " CALL BY VALUE CHECK

FORM CALL_BYVALUE USING VALUE(P_VAL).

  CONCATENATE P_VAL '!!!!!' INTO P_VAL.

  WRITE : / P_VAL. " CALL BY VALUE CHECK!!!!!
 
ENDFORM.


- PERFORM 이후에도 서로 다른 메모리를 공유하기 때문에 파리미터 GV_VAL의 값이 변하지 않은 것을 확인할 수 있다.

- 즉, FORM 구문에서 USING과 VALUE 키워드를 같이 사용하면 새로운 메모리 영역에 값을 복사하여 값을 전달하는 것이다. P_VAL은 FORM내 에서만 쓰이는 지역 변수이다.

 

Call by Reference

- Java 프로그래밍에서 메서드를 호출할 때 변수가 아니라 참조변수를 파라미터로 주는 것과 같다고 볼 수 있다. 참조변수는 객체의 주소값을 가진 변수이기 때문에 파라미터로 참조변수를 던져주면 서브루틴 내에서 객체의 주소값을 가지고 해당 객체를 메모리에서 가져오기 때문에 Actual Parameter와 Formal Parameter가 같아진다.

 

DATA : GV_VAL TYPE C LENGTH 30 VALUE 'CALL BY REFERENCE CHECK'.

WRITE : / GV_VAL. " CALL BY REFERENCE CHECK

PERFORM CALL_BYREF CHANGING GV_VAL. " CALL BY REFERENCE 수행

WRITE : / GV_VAL. " VALUE HAS BEEN CHANGED

FORM CALL_BYREF CHANGING P_VAL.

  P_VAL = 'VALUE HAS BEEN CHANGED'.
 
ENDFORM.

 

 

- VALUE 구문을 쓰지 않으면 USING과 CHANGING 모두 Call by Reference를 이용한다. 하지만 가독성 차원에서 CHANGING을 쓰는 것이 좋을 것이다.

 

 

Call by Value and Result 

- CHANGING 구문과 VALUE 구문이 함께 사용되면 Subroutine이 정상 종료 시 Actual Parameter값이 변경된다. 

DATA : GV_VAL1 TYPE I VALUE 2.
DATA : GV_VAL2 TYPE I VALUE 3.
DATA : GV_SUM  TYPE I.

PERFORM SUM_DATA USING GV_VAL1 GV_VAL2
                                       CHANGING GV_SUM.

WRITE : / 'RESULT : ', GV_SUM.


FORM SUM_DATA USING VALUE(P_VAL1)
                                           VALUE(P_VAL2)
                                CHANGING VALUE(P_SUM).
 
  P_SUM = P_VAL1 + P_VAL2.
 
ENDFORM.

 

 

파라미터

파라미터 타입 정의

- FORM 구문 내의 Formal Parameter는 타입을 명시적으로 지정하지 않으면 Generic Type으로 정의되고 Actual Parameter의 기술적 속성을 상속받게 된다.

- FORM의 Formal Parameter를 I로 지정하고 호출 시 파라미터로 TYPE C를 던져주면 구문 에러가 발생한다.

- Formal Parameter 타입 지정 방식 

1. FORM SUBR CHANGING P_VAL. - Generic Type 사용

2. FORM SUBR CHANGING P_VAL TYPE D. - Actual Parameter와 같은 타입 사용

3. FORM SUBR CHANGING P_VAL LIKE GV_VAL. - Actual Parameter와 같은 타입의 변수 사용

 

 

구조체 파라미터

DATA : BEGIN OF GS_STR,
    COL1 VALUE 'A',
    COL2,
  END OF GS_STR.

GS_STR-COL2 = 'B'.

PERFORM WRITE_DATA USING GS_STR.


FORM WRITE_DATA USING PS_STR STRUCTURE GS_STR.
  WRITE : PS_STR-COL1, PS_STR-COL2.
 
ENDFORM.

 

- 구조체를 파라미터로 전달할 때 타입을 명시적으로 지정하지 않으면 컬럼이 없다는 에러가 발생한다.

- 즉, 구조체를 파라미터로 쓸 때에는 타입을 명시적으로 지정하거나 그렇지 않으면 필드 심볼을 이용해야 한다.

 
DATA : BEGIN OF GS_STR,
    COL1 VALUE 'A',
    COL2,
  END OF GS_STR.

GS_STR-COL2 = 'B'.

FIELD-SYMBOLS <FS>.

PERFORM WRITE_DATA USING GS_STR.


FORM WRITE_DATA USING PS_STR.
 
  ASSIGN COMPONENT 1 OF STRUCTURE PS_STR TO <FS>.
 
  WRITE <FS>.
 
  ASSIGN COMPONENT 2 OF STRUCTURE PS_STR TO <FS>.
 
  WRITE <FS>.
 
ENDFORM.

 

- 위와 같은 결과를 반환한다.

 

인터널 테이블 파라미터

TYPES : BEGIN OF T_STR,
  COL1 TYPE C,
  COL2 TYPE I,
  END OF T_STR.

TYPES : T_ITAB TYPE TABLE OF T_STR.

DATA : GS_STR TYPE T_STR.
DATA : GT_ITAB TYPE T_ITAB.

GS_STR-COL1 = 'A'.
GS_STR-COL2 = 1.
APPEND GS_STR TO GT_ITAB.

GS_STR-COL1 = 'B'.
GS_STR-COL2 = 2.
APPEND GS_STR TO GT_ITAB.

PERFORM TEST_ITAB USING GT_ITAB.

FORM TEST_ITAB USING PT_ITAB TYPE T_ITAB.

  READ TABLE PT_ITAB WITH KEY COL1 = 'A' INTO GS_STR.

  IF SY-SUBRC EQ 0.
    WRITE : GS_STR-COL1, GS_STR-COL2.
  ENDIF.

ENDFORM.
 
 
TABLES 구문
- USING과 CHANGING구문 대신 사용
- 예전 아밥에서 많이 사용되어 현재도 많이 사용되고 또 소스코드에 많이 남아있는 시스템이 많다.
- Call by Value로는 사용할 수 없다.
TYPES : BEGIN OF T_STR,
  COL1 TYPE C,
  COL2 TYPE I,
  END OF T_STR.

TYPES : T_ITAB TYPE TABLE OF T_STR.

DATA : GT_ITAB TYPE T_ITAB.


PERFORM TEST_ITAB TABLES GT_ITAB.

PERFORM WRITE_DATA TABLES GT_ITAB.

FORM TEST_ITAB TABLES PT_ITAB TYPE T_ITAB.

  DATA : LS_STR TYPE T_STR.

  LS_STR-COL1 = 'A'.
  LS_STR-COL2 = 1.
  APPEND LS_STR TO PT_ITAB.

  LS_STR-COL1 = 'B'.
  LS_STR-COL2 = 2.
  APPEND LS_STR TO PT_ITAB.

ENDFORM.

FORM WRITE_DATA TABLES PT_ITAB LIKE GT_ITAB.

  DATA : LS_STR TYPE T_STR.

  LOOP AT PT_ITAB INTO LS_STR.
    WRITE : / LS_STR-COL1, LS_STR-COL2.
  ENDLOOP.

ENDFORM.

 

 

Subroutine 호출

- 서브루틴 호출은 Internal, External 두 가지 방식이 있음

- Internal : 프로그램 내에서 서브루틴 호출

- External : 다른 아밥 프로그램 내의 서브루틴 호출

 

 

REPORT ZABAP_HYOWON_TEST1.

DATA : GV_CHAR(20) VALUE 'EXTERNAL CALL!'.

PERFORM TEST_EXRN_SUBR(ZABAP_HYOWON_4) USING GV_CHAR.

" ================================================

REPORT ZABAP_HYOWON_4.

FORM TEST_EXRN_SUBR USING P_CHAR.

  WRITE : / P_CHAR.

ENDFORM.

 

*ABAP 반복문 3가지 형태

- DO ~ ENDDO : 순환 횟수 지정, 횟수는 SY-INDEX에 저장

DO 3 TIMES.
  PERFORM TEST_EXRN_SUBR(ZABAP_HYOWON_4) USING GV_CHAR.
ENDDO.
 

- WHILE - ENDWHILE : 표현식이 참이면 반복순환, 횟수는 SY-INDEX에 저장

WHILE GV_INDEX < 10.

  PERFORM TEST_EXRN_SUBR(ZABAP_HYOWON_4) USING GV_CHAR.
 
  WRITE : GV_INDEX.
 
  GV_INDEX = GV_INDEX + 1.

ENDWHILE.

 

- LOOP ~ ENDLOOP : 인터널 테이블의 라인을 차례대로 WORK AREA나 HEADER LINE으로 이동하는 순환 구문 

- 현재 순환 횟수는 SY-TABIX에 저장, 인터널 테이블의 라인 번호

LOOP AT PT_ITAB INTO LS_STR.

  WRITE : / LS_STR-COL1, LS_STR-COL2.
 
ENDLOOP.

 

 

 

Subroutine 종료

- EXIT 구문을 만나면 서브루틴 빠져 나오고,

- CHECK 구문을 만나면 값을 비교하여 참이면 이후 구문 수행

- 개인적인 생각으로 IF문을 통해 EXIT 구문을 수행하느냐 마느냐를 정하는 게 소스코드는 길어도 소스코드에 일관성이 있지 않을까함. 다른 언어들도 Return문을 수행하느냐 마느냐로 분기 처리를 하는 경우가 많기 때문에..

 

PARAMETERS : P_VAL TYPE CHAR10.

PERFORM END_SUBR USING P_VAL.

FORM END_SUBR USING VALUE(P_VAL).

  CASE P_VAL.
    WHEN 'EXIT'.
      WRITE 'SUBROUTINE EXIT'.
      EXIT.

    WHEN 'CHECK'.
      WRITE : 'VALUE CHECK : ', P_VAL.
      CHECK P_VAL NE 'CHECK'.

    WHEN OTHERS.

  ENDCASE.

  WRITE 'SUBROUTINE HAS NOMALLY DONE'.

ENDFORM.
 
 
 
 

PERFORM ON COMMIT

- ON COMMIT : COMMIT WORK를 만나면 서브루틴 구문 호출

- ON ROLLBACK : ROLLACK WORK를 만나면 서브루틴 구문 호출

 

DATA : GS_SCARR LIKE SCARR,
      GV_FLG TYPE C.

SELECT SINGLE * FROM SCARR INTO GS_SCARR
  WHERE CARRID = 'AA'.

PERFORM DELETE_DATA USING GS_SCARR.

PERFORM INSERT_DATA ON COMMIT.

IF GV_FLG = 'X'.
  COMMIT WORK.
ENDIF.

FORM DELETE_DATA USING VALUE(PS_SCARR) TYPE SCARR.

  DELETE SCARR FROM PS_SCARR.
  IF SY-SUBRC EQ 0.
    GV_FLG = 'X'.
  ENDIF.

ENDFORM.

FORM INSERT_DATA.
  GS_SCARR-ZCOL1 = 'Z'.
  INSERT SCARR FROM GS_SCARR.
ENDFORM.

 

- COMMIT WORK가 수행될 때 PERFORM INSERT_DATA 구문이 수행되도록 함.

 

 

MACRO

- 같은 구문을 여러 번 사용해야 할 때 미리 구문 덩어리를 매크로라는 하나의 덩어리로 정의하고 계속해서 가져다 쓰는 것이다.

- PERFORM을 사용하는 것과 다르지 않지만 더 소스코드가 짧다는 장점이 있다. "MACRO_NAME 변수." 가 끝이기 때문에 단순하지만 이 구문이 어떤 명령어인지 어디서 왔는지를 알려주는 PERFORM과 같은 명령어가 없어 가독성이 떨어진다. 아마 예전에 SUBROUTINE이나 FUNCTION MODULE 개념이 없었을 때 만들어진 기능이 아닌가 싶다. 안 쓰는 게 좋을 듯.

 

 

 

728x90

'SAP&ABAP' 카테고리의 다른 글

EASY ABAP - 8-1. Internal Table(1)  (0) 2024.04.08
EASY ABAP - 7. Function  (0) 2024.04.08
EASY ABAP - 5. SQL  (1) 2024.04.05
EASY ABAP - 4-2. Data Type(2)  (0) 2024.04.04
EASY ABAP - 4-1. Data Type(1)  (0) 2024.04.04