Was ist “Reflexion” in der Programmierung?

0
258
Shutterstock/whiteMocca

Reflektierende Programmierung ist ein Mechanismus, der einem Prozess introspektive Fähigkeiten ermöglicht. Mit den in Programmiersprachen integrierten Reflection-APIs können Sie Code zur Laufzeit überprüfen. Sie können diese Fähigkeit nutzen, um mehr über die umgebende Codebasis und ihren Inhalt zu erfahren.

Reflexion wird oft im Zusammenhang mit objektorientierter Programmierung erwähnt. Sie verwenden häufig Reflektion, um Codebasisentitäten zur Laufzeit zu erkennen. Mit der Reflektions-API der Sprache können Sie Klassen, Methoden, Eigenschaften und Typen innerhalb Ihres Systems überprüfen. Auf diese Weise können Sie dynamischere Funktionen erstellen.

Systeme, die Reflexion verwenden, sind in der Lage, ihre eigenen Umgebungen abzufragen und zu modifizieren. Hier unterscheidet sich die Reflexion von der reinen Wertintrospektion. Eine Sprache mit vollständiger Reflektionsunterstützung ermöglicht die Änderung der Codebasis zur Laufzeit, wodurch der Quellcode effektiv Aspekte von sich selbst neu schreiben kann.

Ein Beispiel für Reflektion

< p>Eine häufige Verwendung für die Reflexion ist während des Testens. Reflexion kann Ihnen helfen, Klassen zu verspotten, indem Sie ihr internes Verhalten aufdecken. Eine geschützte oder private Klassenmethode wäre normalerweise nicht testbar; Mit Reflektion können Sie die Sichtbarkeitsbeschränkung außer Kraft setzen, damit sie in Ihren Komponententests öffentlich wird.

Klasse Test {   geschützt int $Wert;   öffentliche Funktion __construct(int $Value) { $dies -> Wert = $Wert; }   geschützte Funktion computeValue() : int { ($this -> Wert * 2); }   }   /** * Ohne Spiegelung */  $t = neuer Test(10);   //Fehler – die Methode ist nicht öffentlich zugänglich assert($t -> Rechenwert() === 20);   /** * Spiegelung verwenden */  $reflectionMethod = new ReflectionMethod(Test::CLASS, "computeValue"); $reflexionsmethode -> setAccessible(true);   $t = neuer Test(10);   //Das funktioniert jetzt! assert($reflexionMethod -> ruft ($t) === 20);

In diesem Beispiel mit PHP definiert die Test-Klasse eine geschützte Methode, die intern verwendet wird. Da die Methode eine Berechnung durchführt, möchten Sie sie möglicherweise mit Komponenten testen. Sie können die Methode nicht extern aufrufen, aber mit der Reflection API von PHP können Sie die Sichtbarkeitsbeschränkungen umgehen. Eine ReflectionMethod-Instanz stellt Informationen über die Methode bereit und ermöglicht das Aufrufen einer geänderten Version.

Werbung

Dies ist zwar hilfreich, aber Sie sollten sich bewusst sein, dass es missbraucht werden kann. Die weit verbreitete Verwendung von Reflection beim Testen weist oft auf größere Probleme in Ihrer Codebasis hin. Es impliziert die Klasse’ Schnittstelle ist zu restriktiv und für ihre Aufgaben ungeeignet. In vielen Fällen ist es angemessener, die geschützte Methode in eine neue Klasse umzugestalten, die ihre eigene öffentliche Schnittstelle bereitstellt.

So könnte das für das oben gezeigte Beispiel aussehen:

Klassenrechner {   öffentliche Funktion computeValue() : int { ($this -> Wert * 2); }   }   Klasse Test {   geschützt int $Wert;   geschützt Rechner $Rechner;   öffentliche Funktion __construct(int $Value, Rechner $Calculator) { $dies -> Wert = $Wert; $dies -> Rechner = $Rechner; }   }

Die Rechnerkomponente ist jetzt eine eigenständige Einheit mit einer testbaren öffentlichen Schnittstelle. Dies geht Hand in Hand mit Dependency Injection – die Test-Klasse erhält jetzt einen Rechner, der die Berechnungslogik implementiert.

Reflektion mit unvorhersehbaren Werten verwenden

Reflection ist auch nützlich, wenn Sie generischen Code innerhalb eines Frameworks schreiben. Möglicherweise müssen Sie mit vom Benutzer bereitgestellten Typen interagieren, die Sie nicht erwarten können. Reflection kann hilfreich sein, wenn Sie nicht wissen, welche Methoden und Eigenschaften ein Typ verfügbar macht.

Sie können sich ein Bild von der Funktionalität des Typs machen, ohne seine Quelle vorher zu kennen. Dies ist im Zusammenhang mit Protokollierungs- und Fehlerberichtskomponenten nützlich, die möglicherweise die Mitgliederliste jeder Klasse, die sie übergeben haben, ausgeben möchten.

Auch Datenrangiersysteme werden oft auf diese Weise realisiert. Stellen Sie sich einen Marshaller vor, der eine Klasse nimmt und in eine JSON-Darstellung umwandelt. Sie können eine Konvention definieren, dass jede Methode, die mit get als Präfix versehen ist und mit Json endet (z. B. getUserJson()), vom Marshaller aufgerufen und zu seiner Ausgabe hinzugefügt werden soll. Reflection stellt den Mechanismus bereit, um die Liste der Methoden abzurufen. Anschließend implementieren Sie Logik, um diejenigen zu identifizieren, die Sie aufrufen sollten.

Reflektion, Kompilierung und Assemblierungen

Ankündigung

Reflektion bietet zusätzliche Funktionen in kompilierten Sprachen, die verknüpfte Bibliotheken und Assemblys verwenden. Mit Reflection-APIs können Sie den Inhalt geladener Assemblys überprüfen. In Sprachen wie C# können Sie mithilfe von Reflection-APIs zusätzliche Assemblys dynamisch laden.

Dieser Ansatz kann nützlich sein, wenn Sie ein Plug-in-System mit vom Benutzer bereitgestellten Assemblys implementieren. Ihr Programm weiß nicht, welche Plugins verfügbar sind, wenn es kompiliert wird. Bei jedem Start muss das Dateisystem überprüft werden, um verfügbare Plugin-Assemblys zu finden. Sobald ein Plugin gefunden wurde, bietet Reflection einen Mechanismus zum Laden und Instanziieren seiner Member.

Sie können das Plugin untersuchen, die bereitgestellten Klassen finden und bei Ihrer Anwendung registrieren. Eine weitere Überprüfung der Assembly liefert möglicherweise den Namen und die Version des Plugins zur Anzeige in Ihren Protokollen und in der Benutzeroberfläche.

Reflection kann auch verwendet werden, um Baugruppen basierend auf einer externen Konfiguration auszuwechseln. Angenommen, Sie schreiben eine Anwendung, die Bilddateien im Speicher speichert. Möglicherweise haben Sie einen LocalStorageDriver, FtpStorageDriver und AmazonS3StorageDriver, die jeweils in einer eigenen Assembly enthalten sind (eine .dll in C#).

Mithilfe von Reflection können Sie einen “Speichertreiber” Geben Sie die Konfigurationsdatei Ihres Systems ein. Die entsprechende Assembly wird basierend auf dem Wert Ihrer Konfigurationsdatei dynamisch geladen. Sie würden die Assembly untersuchen, um die Klasse zu ermitteln, die Ihre StorageDriver-Schnittstelle implementiert.

Bei diesem Ansatz können Sie Komponenten Ihres Systems zur Laufzeit austauschen. Sie müssen Ihr Programm nicht neu kompilieren oder neu starten, um zwischen den Assemblys zu wechseln. Dies erhöht die Flexibilität und unterstützt die Implementierung von Konfigurationsanweisungen.

Eval Statements

Werbung

Reflexion ist eng mit eval verbunden. Viele Programmiersprachen bieten eine Möglichkeit, dynamische String-Werte als Quellcode auszuführen.

Eval ist eine Reflexionspermutation mit nahezu unbegrenzter Leistung. Damit können Sie neuen Code innerhalb eines Live-Programms erstellen und ausführen. Dies stellt ein potenziell katastrophales Sicherheitsproblem dar, wenn Benutzereingaben in den eval-String eingegeben werden.

Eine eval-Anweisung sollte verwendet werden, wenn Sie keine anderen Optionen mehr haben. Sie müssen sicherstellen, dass die Anweisung in einem eingeschränkten Kontext ausgeführt wird, der von Benutzern nicht ausgenutzt werden kann. Denken Sie daran, dass eine erfolgreiche Codeinjektion einem Angreifer die gleichen Befugnisse wie Ihr regulärer Anwendungscode verleihen würde.

Schlussfolgerung

Reflexion ist eine Programmiertechnik, die Code introspektive Fähigkeiten verleiht. Durch den effektiven Einsatz von Reflektion können Sie dynamischere Systeme schreiben und von einer erhöhten Automatisierung profitieren. Sie können auch Reflection verwenden, um Komponenten zu testen, die ansonsten nicht erreichbaren privaten Code testen.

Sie müssen jedoch vorsichtig sein. Reflexions-APIs in Programmiersprachen sind mächtig, daher geht mit ihnen die Verantwortung einher. Das größte Problem ist die Fähigkeit der Reflektion, den Schutz Ihrer Programmiersprache zu untergraben.

Reflektion ermöglicht die Existenz von Szenarien, die ansonsten unmöglich wären, wie z. B. Schreibvorgänge in “unveränderlich&#8221 ; Variablen und die weit verbreitete öffentliche Verwendung privater Methoden. Sie sollten darauf vertrauen können, dass Ihr Code die Regeln seiner Sprache respektiert. Die Verwendung der Reflexions-APIs muss daher sorgfältig geprüft und auf bestimmte Abschnitte Ihres Systems beschränkt werden.