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 concretFIELD-SYMBOLS: <fs_name> TYPE <typ>.
" Avec un type génériqueFIELD-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 statiqueASSIGN <variable> TO <fs>.
" Assignation dynamique (nom de champ comme string)ASSIGN (lv_fieldname) TO <fs>.
" Composant d'une structureASSIGN COMPONENT <name_ou_index> OF STRUCTURE <structure> TO <fs>.
" Avec Type-CastingASSIGN <variable> TO <fs> CASTING TYPE <typ>.Champs système
Après ASSIGN :
sy-subrc:0: Assignation réussie4: 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 variableASSIGN lv_number TO <fs_num>.
IF sy-subrc = 0. " Modification via Field-Symbol <fs_num> = 200.
WRITE: / 'Original:', lv_number. " Sortie : 200ENDIF.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'assignationUNASSIGN <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 copieFIELD-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 inlineLOOP AT lt_materials ASSIGNING FIELD-SYMBOL(<fs_inline>). <fs_inline>-menge = <fs_inline>-menge + 50.ENDLOOP.
" Aussi avec READ TABLEREAD 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 composantDO 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 stringlv_name = 'LV_VAR1'.ASSIGN (lv_name) TO <fs_dynamic>.
IF sy-subrc = 0. WRITE: / 'Dynamique :', <fs_dynamic>. " Valeur 1ENDIF.
" 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èresASSIGN lv_hex TO <fs_char> CASTING TYPE c.
WRITE: / <fs_char>. " Sortie : ABCD
" Casting avec structuresDATA: 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 tablesASSIGN 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 2ASSIGN lt_data[ 2 ] TO <fs_line>.
IF sy-subrc = 0. <fs_line> = 'MODIFIÉ'.ENDIF.
" lt_data contient maintenant : Un, MODIFIÉ, Trois10. 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 structurelo_struct_descr ?= cl_abap_typedescr=>describe_by_data( ls_person ).lt_components = lo_struct_descr->components.
" Parcourir tous les composantsLOOP 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)
| Aspect | ASSIGNING (Field-Symbol) | INTO (Zone de travail) |
|---|---|---|
| Copie de données | Non | Oui |
| Performance | Plus rapide | Plus lente |
| Modifications | Directement dans la table | Nécessite MODIFY |
| Mémoire | Minimale | Mémoire supplémentaire |
" LENT : Copier et réécrireLOOP AT lt_materials INTO ls_material. ls_material-preis = ls_material-preis * 2. MODIFY lt_materials FROM ls_material.ENDLOOP.
" RAPIDE : Accès directLOOP 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érifierIF <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 incompatiblesASSIGN lv_string TO <fs_int>.IF sy-subrc <> 0. WRITE: / 'Assignation échouée !'.ENDIF.Remarques importantes / Bonnes pratiques
- Vérifiez toujours
sy-subrcaprèsASSIGNouIS ASSIGNEDavant utilisation. - Utilisez ASSIGNING dans
LOOP ATau 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 TABLEpour un accès individuel efficace.