ABAP FIELD-SYMBOLS et ASSIGN : Accès dynamique aux champs

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Les Field-Symbols sont un concept central en ABAP pour l’accès dynamique aux zones mémoire. Contrairement aux variables normales qui copient les données, un Field-Symbol pointe directement vers la zone mémoire d’une autre variable - similaire aux pointeurs dans d’autres langages de programmation.

Concept de base

  • Un Field-Symbol est un placeholder qui pointe vers une zone mémoire
  • Il est “assigné” à une variable concrète avec ASSIGN
  • Les modifications du Field-Symbol modifient directement la variable originale
  • Pas de copie de données = meilleure performance

Syntaxe

Déclarer un Field-Symbol

" Avec un type concret
FIELD-SYMBOLS: <fs_name> TYPE <typ>.
" Avec un type générique
FIELD-SYMBOLS: <fs_any> TYPE any.
FIELD-SYMBOLS: <fs_data> TYPE data.
FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_structure> TYPE any.
" Déclaration inline (à partir de 7.40)
ASSIGN variable TO FIELD-SYMBOL(<fs_inline>).

Variantes de ASSIGN

" Assignation statique
ASSIGN <variable> TO <fs>.
" Assignation dynamique (nom de champ comme string)
ASSIGN (lv_fieldname) TO <fs>.
" Composant d'une structure
ASSIGN COMPONENT <name_ou_index> OF STRUCTURE <structure> TO <fs>.
" Avec Type-Casting
ASSIGN <variable> TO <fs> CASTING TYPE <typ>.

Champs système

Après ASSIGN :

  • sy-subrc :
    • 0 : Assignation réussie
    • 4 : Assignation échouée (variable n’existe pas ou type incompatible)

Exemples

1. Utilisation de base

DATA: lv_number TYPE i VALUE 100.
FIELD-SYMBOLS: <fs_num> TYPE i.
" Assigner le Field-Symbol à la variable
ASSIGN lv_number TO <fs_num>.
IF sy-subrc = 0.
" Modification via Field-Symbol
<fs_num> = 200.
WRITE: / 'Original:', lv_number. " Sortie : 200
ENDIF.

2. Vérifier un Field-Symbol

FIELD-SYMBOLS: <fs> TYPE any.
" Toujours vérifier avant utilisation !
IF <fs> IS ASSIGNED.
" Field-Symbol pointe vers des données valides
WRITE: / <fs>.
ELSE.
" Field-Symbol n'est pas assigné
WRITE: / 'Field-Symbol non assigné !'.
ENDIF.
" Annuler l'assignation
UNASSIGN <fs>.

3. Field-Symbols avec tables internes (LOOP)

Le cas d’utilisation le plus courant - accès direct aux lignes de table :

TYPES: BEGIN OF ty_material,
matnr TYPE matnr,
menge TYPE i,
preis TYPE p DECIMALS 2,
END OF ty_material.
DATA: lt_materials TYPE TABLE OF ty_material.
lt_materials = VALUE #(
( matnr = 'MAT001' menge = 100 preis = '10.00' )
( matnr = 'MAT002' menge = 200 preis = '20.00' )
( matnr = 'MAT003' menge = 150 preis = '15.00' )
).
" Avec Field-Symbol : Accès direct, pas de copie
FIELD-SYMBOLS: <fs_mat> TYPE ty_material.
LOOP AT lt_materials ASSIGNING <fs_mat>.
" La modification agit directement dans la table
<fs_mat>-preis = <fs_mat>-preis * '1.1'. " Augmentation de 10%
ENDLOOP.
" La table est maintenant modifiée !

4. Déclaration inline de Field-Symbol

" Moderne (à partir de 7.40) : Déclaration inline
LOOP AT lt_materials ASSIGNING FIELD-SYMBOL(<fs_inline>).
<fs_inline>-menge = <fs_inline>-menge + 50.
ENDLOOP.
" Aussi avec READ TABLE
READ TABLE lt_materials ASSIGNING FIELD-SYMBOL(<fs_read>)
WITH KEY matnr = 'MAT001'.
IF sy-subrc = 0.
<fs_read>-preis = 99.
ENDIF.

5. Accès dynamique aux composants de structure

TYPES: BEGIN OF ty_person,
vorname TYPE string,
nachname TYPE string,
alter TYPE i,
END OF ty_person.
DATA: ls_person TYPE ty_person.
FIELD-SYMBOLS: <fs_field> TYPE any.
ls_person = VALUE #( vorname = 'Max' nachname = 'Müller' alter = 30 ).
" Accès via index de composant
DO 3 TIMES.
ASSIGN COMPONENT sy-index OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Champ', sy-index, ':', <fs_field>.
ENDIF.
ENDDO.
" Accès via nom de composant (comme string)
DATA: lv_fieldname TYPE string VALUE 'NACHNAME'.
ASSIGN COMPONENT lv_fieldname OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Nom de famille :', <fs_field>.
ENDIF.

6. Accès dynamique aux variables

DATA: lv_var1 TYPE string VALUE 'Valeur 1',
lv_var2 TYPE string VALUE 'Valeur 2',
lv_name TYPE string.
FIELD-SYMBOLS: <fs_dynamic> TYPE any.
" Nom de variable dynamiquement depuis string
lv_name = 'LV_VAR1'.
ASSIGN (lv_name) TO <fs_dynamic>.
IF sy-subrc = 0.
WRITE: / 'Dynamique :', <fs_dynamic>. " Valeur 1
ENDIF.
" Aussi pour les variables globales avec chemin complet
" ASSIGN ('(PROGRAMNAME)GLOBALVAR') TO <fs>.

7. CASTING - Conversion de type

DATA: lv_hex TYPE x LENGTH 4 VALUE '41424344'.
FIELD-SYMBOLS: <fs_char> TYPE c.
" Interpréter les données hex comme caractères
ASSIGN lv_hex TO <fs_char> CASTING TYPE c.
WRITE: / <fs_char>. " Sortie : ABCD
" Casting avec structures
DATA: lv_raw TYPE x LENGTH 8.
FIELD-SYMBOLS: <fs_struct> TYPE ty_small_struct.
ASSIGN lv_raw TO <fs_struct> CASTING.

8. Field-Symbols génériques

FIELD-SYMBOLS: <fs_any> TYPE any, " N'importe quel type de données
<fs_data> TYPE data, " N'importe quelles données (pas objets)
<fs_table> TYPE ANY TABLE. " N'importe quelle table interne
DATA: lt_any TYPE TABLE OF string.
" Field-Symbol générique pour tables
ASSIGN lt_any TO <fs_table>.
IF <fs_table> IS ASSIGNED.
LOOP AT <fs_table> ASSIGNING <fs_any>.
WRITE: / <fs_any>.
ENDLOOP.
ENDIF.

9. Field-Symbol sur ligne de table avec index

DATA: lt_data TYPE TABLE OF string.
lt_data = VALUE #( ( `Un` ) ( `Deux` ) ( `Trois` ) ).
FIELD-SYMBOLS: <fs_line> TYPE string.
" Accès direct à la ligne 2
ASSIGN lt_data[ 2 ] TO <fs_line>.
IF sy-subrc = 0.
<fs_line> = 'MODIFIÉ'.
ENDIF.
" lt_data contient maintenant : Un, MODIFIÉ, Trois

10. Parcourir dynamiquement des structures imbriquées

DATA: lo_struct_descr TYPE REF TO cl_abap_structdescr,
lt_components TYPE abap_compdescr_tab.
FIELD-SYMBOLS: <fs_comp> TYPE abap_compdescr,
<fs_val> TYPE any.
" Déterminer la description de structure
lo_struct_descr ?= cl_abap_typedescr=>describe_by_data( ls_person ).
lt_components = lo_struct_descr->components.
" Parcourir tous les composants
LOOP AT lt_components ASSIGNING <fs_comp>.
ASSIGN COMPONENT <fs_comp>-name OF STRUCTURE ls_person TO <fs_val>.
IF sy-subrc = 0.
WRITE: / <fs_comp>-name, '=', <fs_val>.
ENDIF.
ENDLOOP.

Field-Symbol vs. INTO (Performance)

AspectASSIGNING (Field-Symbol)INTO (Zone de travail)
Copie de donnéesNonOui
PerformancePlus rapidePlus lente
ModificationsDirectement dans la tableNécessite MODIFY
MémoireMinimaleMémoire supplémentaire
" LENT : Copier et réécrire
LOOP AT lt_materials INTO ls_material.
ls_material-preis = ls_material-preis * 2.
MODIFY lt_materials FROM ls_material.
ENDLOOP.
" RAPIDE : Accès direct
LOOP AT lt_materials ASSIGNING <fs_mat>.
<fs_mat>-preis = <fs_mat>-preis * 2.
ENDLOOP.

Erreurs courantes

1. Utiliser un Field-Symbol non assigné

FIELD-SYMBOLS: <fs> TYPE any.
" ERREUR : Field-Symbol non assigné !
" WRITE: / <fs>. " Erreur d'exécution !
" CORRECT : Toujours vérifier
IF <fs> IS ASSIGNED.
WRITE: / <fs>.
ENDIF.

2. Field-Symbol invalide après modification de table

LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
" ATTENTION : DELETE peut invalider le Field-Symbol !
IF <fs>-status = 'X'.
DELETE lt_data. " <fs> pointe maintenant vers rien !
ENDIF.
ENDLOOP.

3. Incompatibilité de type

DATA: lv_string TYPE string VALUE 'Test'.
FIELD-SYMBOLS: <fs_int> TYPE i.
" ERREUR : Types incompatibles
ASSIGN lv_string TO <fs_int>.
IF sy-subrc <> 0.
WRITE: / 'Assignation échouée !'.
ENDIF.

Remarques importantes / Bonnes pratiques

  • Vérifiez toujours sy-subrc après ASSIGN ou IS ASSIGNED avant utilisation.
  • Utilisez ASSIGNING dans LOOP AT au lieu de INTO pour une meilleure performance.
  • Les Field-Symbols sont idéaux pour la programmation dynamique.
  • Utilisez la déclaration inline (FIELD-SYMBOL(<fs>)) pour un code plus court.
  • Pour les types génériques (TYPE any), le CASTING est souvent nécessaire.
  • Les Field-Symbols peuvent devenir invalides lorsque les données originales sont supprimées.
  • Pour les références d’objets, utilisez plutôt les références de données.
  • Combinez avec READ TABLE pour un accès individuel efficace.