ProgrammationDéveloppeur Backend

Comment fonctionnent les variables lexicales et de package en Perl : quelles sont les différences entre my, our et state, quand les utiliser correctement, et quelles erreurs se rencontrent en pratique ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Perl, il existe trois principaux types de déclaration de variables : my, our et state.

  • my crée une variable lexicale avec une portée dans un bloc de code (portée lexicale).
  • our crée une variable de package, accessible globalement dans le package, mais visible uniquement dans le bloc lexical. Elle est utile pour organiser les espaces de noms entre les modules.
  • state a été ajouté dans Perl 5.10 et crée une variable lexicale qui conserve sa valeur entre les appels de sous-programme (essentiellement une variable statique).
sub example_state { state $counter = 0; $counter++; return $counter; } for (1..3) { print example_state(), " "; # Affichera 1, puis 2, puis 3 }

Où utiliser correctement :

  • my — presque toujours le choix préféré pour les variables, sauf s'il y a une raison pour un accès global.
  • our — pour exporter des variables entre les modules, lorsque le partage est nécessaire.
  • state — lorsque la variable doit "se souvenir" de sa valeur entre les appels de fonction (par exemple, un compteur d'appels).

Question piège

Une variable déclarée avec our peut-elle être capturée dans une closure au même titre que my ?

On répond généralement "oui, c'est pratique", mais ce n'est pas vrai. La variable our est globale au package, et la closure ne lie pas sa valeur au moment de la création de la closure, mais accède via le nom global. Donc, sa "valeur" peut changer en dehors de la closure et affectera toutes les closures !

our $x = 10; my $closure = sub { return $x; }; $x = 42; print $closure->(); # Retournera 42, pas 10

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


Histoire

Dans un grand script de parsing de logs, les variables étaient déclarées via our pour "un accès pratique" depuis différentes fonctions du module. En conséquence, la modification de ces variables dans une fonction entraînait un comportement inattendu dans une autre, brisant le traitement parallèle des logs.


Histoire

L'utilisation de my pour des variables dont la valeur devait être conservée entre les appels de fonction (par exemple, un compteur dans un parcours récursif) entraînait la réinitialisation de la valeur à chaque appel, ce qui provoquait une logique de parcours incorrecte. Le remplacement par state a corrigé la situation.


Histoire

Une utilisation incorrecte de our dans un module importé (export de variables non via Exporter) a provoqué une collision de noms lors de l'importation de deux modules différents utilisant le même nom de variable. En fin de compte, les données "sautaient" d'un contexte à un autre.