Agence web » Actualités du digital » Qu’est-ce que la « réflexion » dans la programmation ? –

Qu’est-ce que la « réflexion » dans la programmation ? –

Shutterstock/blancMocca

La programmation réflexive est un mécanisme qui permet à un processus des capacités d’introspection. Les API de réflexion intégrées aux langages de programmation vous permettent d’inspecter le code lors de l’exécution. Vous pouvez utiliser cette capacité pour en savoir plus sur la base de code environnante et son contenu.

La réflexion est souvent évoquée dans le contexte de la programmation orientée objet. Vous utilisez souvent la réflexion pour découvrir des entités de base de code lors de l’exécution. L’API de réflexion du langage vous permettra d’inspecter les classes, les méthodes, les propriétés et les types depuis votre système. Cela vous permet de créer des fonctionnalités plus dynamiques.

Les systèmes qui utilisent la réflexion sont capables d’interroger et de modifier leurs propres environnements. C’est là que la réflexion diffère de la simple introspection des valeurs. Un langage avec prise en charge complète de la réflexion permettra la modification de la base de code au moment de l’exécution, permettant effectivement à la source de réécrire des aspects d’elle-même.

Un exemple de réflexion

Une utilisation courante de la réflexion est pendant les tests. La réflexion peut vous aider à vous moquer des classes en exposant leurs comportements internes. Une méthode de classe qui protected ou alors private ne serait généralement pas testable ; en utilisant la réflexion, vous pouvez remplacer la contrainte de visibilité pour qu’elle devienne public dans vos tests unitaires.

class Test {
 
    protected int $Value;
 
    public function __construct(int $Value) {
        $this -> Value = $Value;
    }
 
    protected function computeValue() : int {
        return ($this -> Value * 2);
    }
 
}
 
/**
 * Without Reflection
 */
 
$t = new Test(10);
 
// Error - the method isn't publicly accessible
assert($t -> computeValue() === 20);
 
/**
 * Using Reflection
 */
 
$reflectionMethod = new ReflectionMethod(Test::CLASS, "computeValue");
$reflectionMethod -> setAccessible(true);
 
$t = new Test(10);
 
// This now works!
assert($reflectionMethod -> invoke($t) === 20);

Dans cet exemple utilisant PHP, le Test classe définit un protected méthode utilisée en interne. Comme la méthode effectue un calcul, vous souhaiterez peut-être la tester unitairement. Vous ne pouvez pas appeler la méthode en externe, mais l’API de réflexion de PHP vous permet de contourner les contraintes de visibilité. UNE ReflectionMethod instance fournit des informations sur la méthode et vous permet d’invoquer une version modifiée.

Bien que cela soit utile, vous devez être conscient qu’il peut être utilisé à mauvais escient. L’utilisation généralisée de la réflexion dans les tests est souvent révélatrice de problèmes plus importants dans votre base de code. Cela implique que l’interface de la classe est trop restrictive et inadaptée à ses responsabilités. Dans de nombreux cas, il est plus approprié de refactoriser la méthode protégée dans une nouvelle classe qui expose sa propre interface publique.

Voici à quoi cela pourrait ressembler pour l’exemple ci-dessus :

class Calculator {
 
    public function computeValue() : int {
        return ($this -> Value * 2);
    }
 
}
 
class Test {
 
    protected int $Value;
 
    protected Calculator $Calculator;
 
    public function __construct(int $Value, Calculator $Calculator) {
        $this -> Value = $Value;
        $this -> Calculator = $Calculator;
    }
 
}

Le composant calculateur est maintenant sa propre unité autonome avec une interface publique testable. Cela va de pair avec l’injection de dépendances – le Test la classe reçoit maintenant un Calculator qui implémente la logique de calcul.

Utilisation de la réflexion avec des valeurs imprévisibles

La réflexion est également utile lorsque vous écrivez du code générique dans un framework. Vous devrez peut-être vous connecter à des types fournis par l’utilisateur que vous ne pouvez pas anticiper. La réflexion peut être utile lorsque vous ne savez pas quelles méthodes et propriétés un type expose.

Vous pouvez obtenir une image de la fonctionnalité du type sans aucune connaissance préalable de sa source. Ceci est utile dans le contexte des composants de journalisation et de rapport d’erreurs qui peuvent vouloir vider la liste des membres de toute classe qui leur est transmise.

Les systèmes de tri des données sont souvent mis en œuvre de cette manière également. Imaginez un marshaller qui prend une classe et la convertit en une représentation JSON. Vous pouvez définir une convention selon laquelle toute méthode préfixée par get et se termine par Json (par exemple getUserJson()) doit être appelé par le marshaller et ajouté à sa sortie. Reflection fournit le mécanisme pour obtenir la liste des méthodes. Vous devez ensuite implémenter une logique pour identifier ceux que vous devez appeler.

Réflexion, compilation et assemblage

Reflection fournit des fonctionnalités supplémentaires dans les langages compilés qui utilisent des bibliothèques et des assemblys liés. Les API de réflexion vous permettent d’inspecter le contenu des assemblys chargés. Dans des langages tels que C#, vous pouvez charger dynamiquement des assemblys supplémentaires à l’aide des API de réflexion.

Cette approche peut être utile si vous implémentez un système de plug-in avec des assemblys fournis par l’utilisateur. Votre programme ne saura pas quels plugins sont disponibles lorsqu’il sera compilé. Chaque fois qu’il se lance, il devra vérifier le système de fichiers pour trouver les assemblages de plugins disponibles. Une fois qu’un plugin a été trouvé, Reflection fournit un mécanisme pour charger et instancier ses membres.

Vous pouvez inspecter le plugin, trouver les classes qu’il fournit et l’enregistrer avec votre application. Une inspection plus approfondie de l’assemblage peut fournir le nom et la version du plug-in à afficher dans vos journaux et votre interface utilisateur.

La réflexion peut également être utilisée pour désactiver les assemblages en fonction de la configuration externe. Disons que vous écrivez une application qui enregistre les fichiers image sur le stockage. Vous pourriez avoir un LocalStorageDriver, FtpStorageDriver et AmazonS3StorageDriver, chacun contenu dans son propre assemblage (un .dll en C#).

En utilisant la réflexion, vous pouvez proposer une clé de « pilote de stockage » dans le fichier de configuration de votre système. L’assembly approprié serait chargé dynamiquement en fonction de la valeur de votre fichier de configuration. Vous inspecteriez l’assembly pour découvrir la classe qui implémente votre StorageDriver interface.

Cette approche vous permet de changer les composants de votre système au moment de l’exécution. Vous n’avez pas besoin de recompiler ou de redémarrer votre programme pour passer d’un assembly à l’autre. Cela vous donne une flexibilité accrue et aide à la mise en œuvre des directives de configuration.

Déclarations d’évaluation

La réflexion est étroitement liée à eval. De nombreux langages de programmation offrent un moyen d’exécuter des valeurs de chaîne dynamiques en tant que code source.

Eval est une permutation de réflexion avec un pouvoir presque illimité. Il vous permet de créer et d’exécuter un nouveau code dans un programme en direct. Cela pose un problème de sécurité potentiellement catastrophique si l’entrée de l’utilisateur est introduite dans le eval chaîne.

Une instruction eval doit être utilisée lorsque vous n’avez plus d’autres options. Vous devez vous assurer que l’instruction est exécutée dans un contexte restreint qui ne peut pas être exploité par les utilisateurs. N’oubliez pas qu’une injection de code réussie donnerait à un attaquant les mêmes pouvoirs que votre code d’application habituel.

Conclusion

La réflexion est une technique de programmation qui donne des capacités d’introspection du code. L’utilisation efficace de la réflexion vous permet d’écrire des systèmes plus dynamiques et de bénéficier d’une automatisation accrue. Vous pouvez également utiliser la réflexion pour tester unitairement du code privé autrement inaccessible.

Vous devez faire preuve de prudence. Les API de réflexion dans les langages de programmation sont puissantes, donc avec elles vient la responsabilité. Le plus gros problème est la capacité de la réflexion à subvertir les protections fournies par votre langage de programmation.

La réflexion permet l’existence de scénarios qui seraient autrement impossibles, tels que l’écriture de variables « immuables » et l’utilisation publique généralisée de méthodes privées. Vous devez pouvoir faire confiance à votre code pour respecter les règles de son langage. L’utilisation des API de réflexion doit donc être soigneusement étudiée et limitée à des sections spécifiques de votre système.

★★★★★