References de donnees ABAP : REF, GET REFERENCE et dereferencement

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Les references de donnees en ABAP sont des pointeurs types qui pointent vers des objets de donnees en memoire. Contrairement aux Field-Symbols, qui pointent directement vers la memoire, les references de donnees sont des variables autonomes qui stockent une adresse.

Concept de base

  • Une reference de donnees est une variable qui contient l’adresse memoire d’un objet de donnees
  • Elle peut etre transmise, stockee et comparee
  • L’acces aux donnees se fait par dereferencement (->*)
  • Les references de donnees peuvent etre initiales (NULL)

Syntaxe

Declarer une reference de donnees

" Reference typee
DATA: lr_data TYPE REF TO <type_donnees>.
" Reference generique (vers des donnees quelconques)
DATA: lr_any TYPE REF TO data.
" Declaration inline
DATA(lr_inline) = REF #( variable ).

Creer une reference

" Moderne (depuis 7.40) : REF #()
lr_data = REF #( variable ).
" Classique : GET REFERENCE
GET REFERENCE OF variable INTO lr_data.
" Creer un nouvel objet de donnees
CREATE DATA lr_data TYPE <typ>.
lr_data = NEW #( ). " Depuis 7.40

Dereferencement

" Acces aux donnees
<valeur> = lr_data->*.
" Pour les structures : acces aux composants
<valeur> = lr_struct->comp_name.
" Pour les tables : acces aux lignes
LOOP AT lr_table->* INTO DATA(ls_line).
...
ENDLOOP.

Champs systeme

Apres les operations avec les references de donnees :

  • Reference IS BOUND : pointe vers des donnees valides
  • Reference IS INITIAL : ne pointe vers rien (NULL)

Exemples

1. Utilisation de base

DATA: lv_number TYPE i VALUE 42.
DATA: lr_number TYPE REF TO i.
" Creer une reference vers une variable
lr_number = REF #( lv_number ).
" Dereferencement : lire la valeur
WRITE: / 'Valeur:', lr_number->*. " 42
" Dereferencement : modifier la valeur
lr_number->* = 100.
WRITE: / 'Original:', lv_number. " 100 (modifie !)

2. Verifier une reference

DATA: lr_data TYPE REF TO string.
" Verifier si la reference est valide
IF lr_data IS BOUND.
WRITE: / 'La reference pointe vers:', lr_data->*.
ELSE.
WRITE: / 'La reference est NULL'.
ENDIF.
IF lr_data IS INITIAL.
WRITE: / 'Reference non initialisee'.
ENDIF.
" Liberer la reference
FREE lr_data.

3. GET REFERENCE (syntaxe classique)

DATA: lv_text TYPE string VALUE 'Bonjour le monde'.
DATA: lr_text TYPE REF TO string.
" Syntaxe classique
GET REFERENCE OF lv_text INTO lr_text.
WRITE: / lr_text->*. " Bonjour le monde

4. Creer un nouvel objet de donnees

DATA: lr_number TYPE REF TO i.
" Classique : CREATE DATA
CREATE DATA lr_number.
lr_number->* = 42.
" Moderne : NEW #()
DATA(lr_string) = NEW string( 'Nouvelle chaine' ).
WRITE: / lr_string->*.
" Avec type
DATA: lr_any TYPE REF TO data.
CREATE DATA lr_any TYPE i.
" Generique avec type dynamique
DATA: lv_typename TYPE string VALUE 'STRING'.
CREATE DATA lr_any TYPE (lv_typename).

5. References avec tables internes

TYPES: BEGIN OF ty_customer,
id TYPE i,
name TYPE string,
END OF ty_customer.
DATA: lt_customers TYPE TABLE OF ty_customer,
lr_table TYPE REF TO ty_customer.
lt_customers = VALUE #(
( id = 1 name = 'Muller' )
( id = 2 name = 'Schmidt' )
).
" REFERENCE INTO dans LOOP
LOOP AT lt_customers REFERENCE INTO lr_table.
WRITE: / lr_table->id, lr_table->name.
" Modification via reference
lr_table->name = to_upper( lr_table->name ).
ENDLOOP.
" READ TABLE avec REFERENCE INTO
READ TABLE lt_customers REFERENCE INTO lr_table
WITH KEY id = 1.
IF sy-subrc = 0.
lr_table->name = 'Modifie'.
ENDIF.

6. Stocker des references dans des tables

DATA: lt_refs TYPE TABLE OF REF TO string.
DATA: lv_str1 TYPE string VALUE 'Un',
lv_str2 TYPE string VALUE 'Deux',
lv_str3 TYPE string VALUE 'Trois'.
" Collecter des references
APPEND REF #( lv_str1 ) TO lt_refs.
APPEND REF #( lv_str2 ) TO lt_refs.
APPEND REF #( lv_str3 ) TO lt_refs.
" Parcourir les references
LOOP AT lt_refs INTO DATA(lr_str).
WRITE: / lr_str->*.
ENDLOOP.
" Modifier les valeurs originales via les references
READ TABLE lt_refs INTO lr_str INDEX 1.
lr_str->* = 'MODIFIE'.
WRITE: / lv_str1. " MODIFIE

7. Passer des references aux methodes

CLASS lcl_processor DEFINITION.
PUBLIC SECTION.
METHODS: process_data IMPORTING ir_data TYPE REF TO i.
ENDCLASS.
CLASS lcl_processor IMPLEMENTATION.
METHOD process_data.
IF ir_data IS BOUND.
ir_data->* = ir_data->* * 2.
ENDIF.
ENDMETHOD.
ENDCLASS.
" Utilisation
DATA: lv_value TYPE i VALUE 50,
lo_proc TYPE REF TO lcl_processor.
lo_proc = NEW #( ).
lo_proc->process_data( REF #( lv_value ) ).
WRITE: / lv_value. " 100

8. References generiques (REF TO data)

DATA: lr_any TYPE REF TO data.
FIELD-SYMBOLS: <fs_data> TYPE any.
" Reference vers Integer
DATA(lv_int) = 42.
lr_any = REF #( lv_int ).
" Pour l'acces : assigner un Field-Symbol
ASSIGN lr_any->* TO <fs_data>.
WRITE: / <fs_data>.
" Reference vers String
DATA(lv_str) = |Bonjour|.
lr_any = REF #( lv_str ).
ASSIGN lr_any->* TO <fs_data>.
WRITE: / <fs_data>.

9. Creation dynamique d’objets

DATA: lr_data TYPE REF TO data,
lv_type TYPE string VALUE 'STRING'.
" Creer dynamiquement un objet de donnees
CREATE DATA lr_data TYPE (lv_type).
" Assigner une valeur via Field-Symbol
FIELD-SYMBOLS: <fs> TYPE any.
ASSIGN lr_data->* TO <fs>.
<fs> = 'Cree dynamiquement'.
WRITE: / <fs>.
" Pour les structures
DATA: lv_struct_name TYPE string VALUE 'SFLIGHT'.
CREATE DATA lr_data TYPE (lv_struct_name).
ASSIGN lr_data->* TO <fs>.

10. Comparaison de references

DATA: lv_data TYPE string VALUE 'Test'.
DATA: lr_ref1 TYPE REF TO string,
lr_ref2 TYPE REF TO string,
lr_ref3 TYPE REF TO string.
lr_ref1 = REF #( lv_data ).
lr_ref2 = REF #( lv_data ).
lr_ref3 = lr_ref1.
" Comparaison de references (pointent vers la meme adresse ?)
IF lr_ref1 = lr_ref3.
WRITE: / 'ref1 et ref3 sont identiques'. " Oui
ENDIF.
IF lr_ref1 = lr_ref2.
WRITE: / 'ref1 et ref2 sont identiques'. " Non ! (references differentes)
ENDIF.
" Comparaison de valeurs
IF lr_ref1->* = lr_ref2->*.
WRITE: / 'Les valeurs sont egales'. " Oui
ENDIF.

Reference de donnees vs Field-Symbol

AspectReference de donneesField-Symbol
TypeVariable (REF TO)Espace reserve
StockageOui, peut etre stockeeNon, seulement temporaire
TransmissionPeut etre passee en parametreUtilisable localement seulement
Etat NULLPeut etre initial/non lieeNon assignee
Syntaxelr_data->*<fs>
PerformanceLegerement plus lentLegerement plus rapide
ApplicationStockage, transmissionAcces local rapide
" Field-Symbol : acces local rapide
LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
<fs>-field = 'X'.
ENDLOOP.
" Reference de donnees : quand la reference doit etre stockee
LOOP AT lt_data REFERENCE INTO DATA(lr_line).
APPEND lr_line TO lt_references. " Stocker la reference
ENDLOOP.

Cas d’utilisation typiques

1. Parametres optionnels

METHODS: process
IMPORTING ir_config TYPE REF TO ty_config OPTIONAL.
METHOD process.
IF ir_config IS BOUND.
" Utiliser la configuration
ELSE.
" Valeurs par defaut
ENDIF.
ENDMETHOD.

2. Retour de references

METHODS: get_instance
RETURNING VALUE(rr_instance) TYPE REF TO lcl_singleton.
METHOD get_instance.
IF gr_instance IS NOT BOUND.
gr_instance = NEW #( ).
ENDIF.
rr_instance = gr_instance.
ENDMETHOD.

3. Structures de donnees dynamiques

" Structure arborescente avec references
TYPES: BEGIN OF ty_node,
value TYPE string,
children TYPE TABLE OF REF TO ty_node WITH EMPTY KEY,
END OF ty_node.
DATA: lr_root TYPE REF TO ty_node.
lr_root = NEW #( value = 'Racine' ).
APPEND NEW ty_node( value = 'Enfant 1' ) TO lr_root->children.

Remarques importantes / Bonnes pratiques

  • Verifiez toujours IS BOUND avant le dereferencement.
  • Utilisez REF #() au lieu de GET REFERENCE dans l’ABAP moderne.
  • Les Field-Symbols sont plus performants pour l’acces local.
  • Les references de donnees sont necessaires lorsque les references doivent etre stockees ou transmises.
  • CREATE DATA pour la determination dynamique du type a l’execution.
  • Attention aux references generiques (REF TO data) - la securite de type est perdue.
  • Combinez avec LOOP AT ... REFERENCE INTO pour un acces efficace aux tables.
  • Utilisez les references dans les attributs de CLASS pour les relations entre objets.