Vad är “reflektion” i programmering?

0
166
Shutterstock/whiteMocca

Reflekterande programmering är en mekanism som låter en process introspektiv kapacitet. Reflektions-API: er inbyggda i programmeringsspråk gör att du kan inspektera kod vid körning. Du kan använda denna förmåga för att lära dig mer om den omgivande kodbasen och dess innehåll.

Reflektion talas ofta om i samband med objektorienterad programmering. Du använder ofta reflektion för att upptäcka kodbaserade enheter vid körning. Språkets API för reflektion låter dig inspektera klasser, metoder, egenskaper och typer från ditt system. Detta låter dig bygga mer dynamisk funktionalitet.

System som använder reflektion kan förhöra och modifiera sina egna miljöer. Det är här reflektion skiljer sig från självtänksamhet. Ett språk med fullständigt reflektionsstöd möjliggör modebasändring vid körning, vilket effektivt gör det möjligt för källan att skriva om aspekter av sig själv. p>En vanlig användning för reflektion är under testning. Reflektion kan hjälpa dig att håna klasser genom att avslöja deras interna beteende. En klassmetod som är skyddad eller privat kan vanligtvis inte testas; med reflektion kan du åsidosätta synbarhetsbegränsningen så att den blir offentlig i dina enhetstester.

klass Test & # 123; & nbsp; skyddat int $ värde; & nbsp; offentlig funktion __construct & # 40; int $ Value & # 41; & # 123; $ detta – & gt; Värde = $ Värde; & # 125; & nbsp; skyddad funktion computeValue & # 40; & # 41; : int & # 123; returnera & # 40; $ detta – & gt; Värde * 2 & # 41 ;; & # 125; & nbsp; & # 125; & nbsp;/** * Utan reflektion */& nbsp; $ t = nytt test & # 40; 10 & # 41 ;; & nbsp; //Fel – metoden är inte offentligt tillgänglig påstå & # 40; $ t – & gt; beräkningsvärde & # 40; & # 41; === 20 & # 41 ;; & nbsp;/** * Använda reflektion */& nbsp; $ reflectMethod = new ReflectionMethod & # 40; Test :: CLASS, & quot; computeValue & quot; & # 41 ;; $ reflexionsmetod – & gt; setAccessible & # 40; true & # 41 ;; & nbsp; $ t = nytt test & # 40; 10 & # 41 ;; & nbsp; //Det här fungerar nu! hävda & # 40; $ reflektionsmetod – & gt; åberopa & # 40; $ t & # 41; === 20 & # 41 ;;

I detta exempel med PHP definierar testklassen en skyddad metod som används internt. Eftersom metoden utför en beräkning kanske du vill testa enheten. Du kan inte ringa metoden externt, men PHP: s Reflection API låter dig kringgå synlighetsbegränsningarna. En ReflectionMethod-instans ger information om metoden och låter dig åberopa en modifierad version.

Annons

Även om detta är till hjälp bör du vara medveten om att det kan missbrukas. Utbredd användning av reflektion vid testning är ofta ett tecken på större problem i din kodbas. Det innebär att klassen & # 8217; gränssnittet är alltför begränsande och olämpligt för dess ansvar. I många fall är det mer lämpligt att omforma den skyddade metoden till en ny klass som exponerar sitt eget offentliga gränssnitt.

Så här kan det se ut för exemplet som visas ovan:

klasskalkylator & # 123; & nbsp; public function computeValue & # 40; & # 41; : int & # 123; returnera & # 40; $ detta – & gt; Värde * 2 & # 41 ;; & # 125; & nbsp; & # 125; & nbsp; klass Test & # 123; & nbsp; skyddat int $ värde; & nbsp; skyddad miniräknare $ miniräknare; & nbsp; offentlig funktion __construct & # 40; int $ Value, Calculator $ Calculator & # 41; & # 123; $ detta – & gt; Värde = $ Värde; $ detta – & gt; Kalkylator = $ Kalkylator; & # 125; & nbsp; & # 125;

Kalkylatorkomponenten är nu en egen fristående enhet med ett testbart offentligt gränssnitt. Detta går hand i hand med beroendeinjektion & # 8211; testklassen får nu en kalkylator som implementerar beräkningslogiken.

Använda reflektion med oförutsägbara värden

Reflektion är också användbar när du skriver generisk kod inom ett ramverk. Du kan behöva gränssnitt med användartillverkade typer som du inte kan förutse. Reflektion kan hjälpa till när du inte vet vilka metoder och egenskaper en typ exponerar.

Du kan få en bild av typens funktionalitet utan någon tidigare kännedom om källan. Detta är användbart i samband med loggning och felrapporteringskomponenter som kanske vill dumpa medlemslistan för alla klasser de har passerat.

Datamarkeringssystem implementeras ofta också på detta sätt. Föreställ dig en marshaller som tar en klass och omvandlar den till en JSON-representation. Du kan definiera en konvention att vilken metod som helst före get och slutar med Json (t.ex. getUserJson ()) ska anropas av marshaller och läggas till dess utdata. Reflektion tillhandahåller mekanismen för att få en lista över metoder. Du implementerar sedan logik för att identifiera de du ska ringa.

Reflektion, sammanställning och sammansättning

Annonsering

Reflektion ger ytterligare funktioner på kompilerade språk som använder länkade bibliotek och sammansättningar. Reflection API: er låter dig inspektera innehållet i laddade enheter. På språk som C # kan du ladda ytterligare enheter dynamiskt genom att använda Reflection API: er.

Detta tillvägagångssätt kan vara användbart om du implementerar ett pluginsystem med användarlevererade enheter. Ditt program vet inte vilka plugins som är tillgängliga när det sammanställs. Varje gång den startar måste den kontrollera filsystemet för att hitta tillgängliga plugin-enheter. När ett plugin har hittats tillhandahåller Reflection en mekanism för att ladda och starta sina medlemmar.

Du kan inspektera plugin-programmet, hitta de klasser det ger och registrera det med din applikation. Ytterligare inspektion av enheten kan ge pluginns namn och version för visning i dina loggar och användargränssnitt.

Reflektion kan också användas för att stänga av enheter baserat på extern konfiguration. Låt oss säga att du skriver ett program som sparar bildfiler till lagring. Du kanske har en LocalStorageDriver, FtpStorageDriver och AmazonS3StorageDriver, som alla finns i sin egen samling (en .dll i C #).

Med hjälp av reflektion kan du erbjuda en & # 8220; lagringsdrivrutin & # 8221; knappa in systemets konfigurationsfil. Lämplig montering laddas dynamiskt baserat på din konfigurationsfils värde. Du inspekterar enheten för att upptäcka klassen som implementerar ditt StorageDriver-gränssnitt.

Denna metod gör att du kan byta ut komponenter i ditt system vid körning. Du behöver inte kompilera om eller starta om ditt program för att växla mellan enheterna. Detta ger dig ökad flexibilitet och hjälper till med implementeringen av konfigurationsdirektiven.

Eval Statements

Annons

Reflektion är nära relaterad till eval. Många programmeringsspråk ger ett sätt att utföra dynamiska strängvärden som källkod.

Eval är en reflektionspermutation med nästan obegränsad kraft. Det låter dig skapa och köra ny kod i ett liveprogram. Detta utgör ett potentiellt katastrofalt säkerhetsproblem om användarinmatningen matas in i eval-strängen.

Ett eval uttalande bör användas när du inte har några andra alternativ. Du måste se till att uttalandet körs i ett begränsat sammanhang som inte kan utnyttjas av användare. Kom ihåg att en framgångsrik kodinjektion skulle ge en angripare samma befogenheter som din vanliga applikationskod.

Slutsats

Reflektion är en programmeringsteknik som ger koden introspektiva förmågor. Effektiv reflektionsanvändning låter dig skriva mer dynamiska system och dra nytta av ökad automatisering. Du kan också använda reflektion för att testa en annan, oåtkomlig privat kod.

Du måste vara försiktig. Reflektions-API: er på programmeringsspråk är kraftfulla så med dem kommer ansvaret. Det största problemet är reflektionens förmåga att undergräva skyddet från ditt programmeringsspråk.

Reflektion tillåter att det finns scenarier som annars skulle vara omöjliga, som att skriva till & # 8220; oföränderlig & # 8221 ; variabler och utbredd allmän användning av privata metoder. Du bör kunna lita på din kod för att respektera reglerna för dess språk. Användningen av reflektions-API: erna måste därför övervägas noggrant och omfattas av specifika delar av ditt system.