Programação reflexiva

Da Wikipédia, a enciclopédia livre
Ir para a navegação Saltar para pesquisar

Na ciência da computação , programação reflexiva ou reflexão é a capacidade de um processo de examinar, introspectar e modificar sua própria estrutura e comportamento. [1]

Antecedentes históricos

Os primeiros computadores foram programados em suas linguagens de montagem nativas , que eram inerentemente reflexivas, pois essas arquiteturas originais podiam ser programadas definindo instruções como dados e usando código automodificável . À medida que a maior parte da programação mudou para linguagens compiladas de nível superior , como Algol , Cobol , Fortran , Pascal e C , essa capacidade reflexiva desapareceu em grande parte até que surgiram novas linguagens de programação com reflexão incorporada em seus sistemas de tipos. [ citação necessária ]

A dissertação de doutorado de Brian Cantwell Smith em 1982 introduziu a noção de reflexão computacional em linguagens de programação procedural e a noção de intérprete metacircular como um componente do 3-Lisp . [2] [3]

Usa

O Reflection ajuda os programadores a criar bibliotecas de software genéricas para exibir dados, processar diferentes formatos de dados, executar serialização ou desserialização de dados para comunicação ou agrupar e desagrupar dados para contêineres ou rajadas de comunicação.

O uso eficaz da reflexão quase sempre requer um plano: uma estrutura de design, descrição de codificação, biblioteca de objetos, um mapa de um banco de dados ou relações de entidade.

A reflexão torna uma linguagem mais adequada ao código orientado à rede. Por exemplo, ele ajuda linguagens como Java a operar bem em redes, habilitando bibliotecas para serialização, agrupamento e formatos de dados variados. Linguagens sem reflexão como C são obrigadas a usar compiladores auxiliares para tarefas como Abstract Syntax Notation para produzir código para serialização e empacotamento.

A reflexão pode ser usada para observar e modificar a execução do programa em tempo de execução . Um componente de programa orientado à reflexão pode monitorar a execução de um compartimento de código e pode modificar-se de acordo com um objetivo desejado desse compartimento. Isso geralmente é feito atribuindo código de programa dinamicamente em tempo de execução.

Em linguagens de programação orientadas a objetos como Java , a reflexão permite a inspeção de classes, interfaces, campos e métodos em tempo de execução sem saber os nomes das interfaces, campos, métodos em tempo de compilação . Também permite a instanciação de novos objetos e invocação de métodos.

A reflexão é frequentemente usada como parte do teste de software , como para a criação/instanciação de objetos simulados em tempo de execução .

A reflexão também é uma estratégia chave para a metaprogramação .

Em algumas linguagens de programação orientadas a objetos, como C# e Java , a reflexão pode ser usada para ignorar as regras de acessibilidade de membros . Para propriedades C#, isso pode ser feito escrevendo diretamente no campo de apoio (geralmente invisível) de uma propriedade não pública. Também é possível encontrar métodos não públicos de classes e tipos e invocá-los manualmente. Isso funciona para arquivos internos do projeto, bem como bibliotecas externas, como assemblies do .NET e arquivos do Java.

Implementação

Uma reflexão de suporte de linguagem fornece vários recursos disponíveis em tempo de execução que, de outra forma, seriam difíceis de realizar em uma linguagem de nível inferior. Alguns desses recursos são as habilidades de:

  • Descubra e modifique construções de código-fonte (como blocos de código, classes , métodos, protocolos etc.) como objetos de primeira classe em tempo de execução .
  • Converta uma string que corresponda ao nome simbólico de uma classe ou função em uma referência ou invocação dessa classe ou função.
  • Avalie uma string como se fosse uma instrução de código-fonte em tempo de execução.
  • Crie um novo interpretador para o bytecode da linguagem para dar um novo significado ou propósito para uma construção de programação.

Esses recursos podem ser implementados de diferentes maneiras. No MOO , a reflexão é uma parte natural da linguagem de programação cotidiana. Quando os verbos (métodos) são chamados, várias variáveis ​​como verb (o nome do verbo que está sendo chamado) e this (o objeto no qual o verbo é chamado) são preenchidas para fornecer o contexto da chamada. A segurança é normalmente gerenciada acessando a pilha de chamadores programaticamente: Como callers () é uma lista dos métodos pelos quais o verbo atual foi eventualmente chamado, realizar testes em callers ()[0] (o comando invocado pelo usuário original) permite que o verbo para se proteger contra o uso não autorizado.

As linguagens compiladas dependem de seu sistema de tempo de execução para fornecer informações sobre o código-fonte. Um executável Objective-C compilado , por exemplo, registra os nomes de todos os métodos em um bloco do executável, fornecendo uma tabela para corresponder esses métodos aos métodos subjacentes (ou seletores para esses métodos) compilados no programa. Em uma linguagem compilada que dá suporte à criação de funções em tempo de execução, como Common Lisp , o ambiente de tempo de execução deve incluir um compilador ou um interpretador.

A reflexão pode ser implementada para idiomas sem reflexão integrada usando um sistema de transformação de programa para definir alterações automatizadas de código-fonte.

Considerações de segurança

A reflexão pode permitir que um usuário crie caminhos de fluxo de controle inesperados por meio de um aplicativo, potencialmente ignorando as medidas de segurança. Isso pode ser explorado por invasores. [4] Vulnerabilidades históricas em Java causadas por reflexão insegura permitiram que código recuperado de máquinas remotas potencialmente não confiáveis ​​quebrasse o mecanismo de segurança de sandbox Java. Um estudo em grande escala de 120 vulnerabilidades Java em 2013 concluiu que reflexão insegura é a vulnerabilidade mais comum em Java, embora não seja a mais explorada. [5]

Exemplos

Os trechos de código a seguir criam uma instância foo de classe Foo e invocam seu método PrintHello . Para cada linguagem de programação , são mostradas sequências de chamadas normais e baseadas em reflexão.

C#

Segue um exemplo em C# :

// Sem reflexão 
Foo  foo  =  new  Foo (); 
foo . ImprimirOlá ();

// Com reflexão 
Object  foo  =  Activator . CreateInstance ( "complete.classpath.and.Foo" ); 
Método MethodInfo  = foo . GetType (). GetMethod ( "PrintHello" ); método . Invoke ( foo , null );  
 

Delphi / Object Pascal

Este exemplo Delphi / Object Pascal assume que uma classe TFoo foi declarada em uma unidade chamada Unit1 :

usa  RTTI ,  Unidade1 ;

procedimento  Sem Reflexão ; 
var 
  Foo :  TFoo ; 
begin 
  Foo  :=  TFoo . Criar ; 
  tente 
    Foo . Olá ; 
  finalmente 
    Foo . Grátis ; 
  fim ; 
fim ;

procedimento  WithReflection ; 
var 
  RttiContext :  TRttiContext ; 
  RttiType :  TRttiInstanceType ; 
  Foo :  TObject ; 
begin 
  RttiType  :=  RttiContext . FindType ( 'Unit1.TFoo' )  como  TRttiInstanceType ; 
  GetMethod ( 'Criar' ) . Invoque ( RttiType . MetaclassType , []) . AsObject ;   
  tente 
    RttiType . GetMethod ( 'Olá' ) . Invocar ( Foo ,  []) ; 
  finalmente 
    Foo . Grátis ; 
  fim ; 
fim ;

eC

O seguinte é um exemplo em eC :

// Sem reflexão 
Foo foo { };   
foo . ola ();

// Com reflexão 
Classe fooClass = eSystem_FindClass ( __thisModule , "Foo" );    
Instância foo = eInstance_New ( fooClass );   
Método m = eClass_FindMethod ( fooClass , "hello" , fooClass . module );     
(( void ( * )())( void * ) m . function )( foo );  

Ir

O seguinte é um exemplo em Go :

importar  "refletir"

// Sem reflexão 
f  :=  Foo {} 
f . Olá ()

// Com reflexão 
fT  :=  reflectir . TypeOf ( Foo {}) 
fV  :=  reflectir . Novo ( fT )

m  :=  fV . MethodByName ( "Olá" ) 
if  m . Chamar ( nulo ) } 
    

Java

Segue um exemplo em Java :

import  java.lang.reflect.Method ;

// Sem reflexão 
Foo  foo  =  new  Foo (); 
foo . ola ();

// Com reflexão 
try  { 
    Object  foo  =  Foo . getDeclaredConstructor (). novaInstância ();

    Método  m  =  foo . getClass (). m . invocar ( foo ); } catch ( ReflectiveOperationException ignorado ) {}  
    
    

JavaScript

Segue um exemplo em JavaScript :

// Sem reflexão 
const  foo  =  new  Foo () 
foo . olá ()

// Com reflexão 
const  foo  =  Reflect . construct ( Foo ) 
const  hello  =  Reflect . get ( foo ,  'olá' ) 
Refletir . aplicar ( olá ,  foo ,  [])

// Com eval 
eval ( 'new Foo().hello()' )

Júlia

O seguinte é um exemplo em Julia (linguagem de programação) :

julia>  struct  Point 
           x :: Int 
           y 
       end

# Inspeção com reflexão 
julia>  fieldnames ( Point ) 
(:x, :y)

julia>  tipos de campo ( Point ) 
(Int64, Any)

julia>  p  =  Ponto ( 3 , 4 )

# Acesso com reflexão 
julia>  getfield ( p ,  :x ) 
3

Objective-C

O seguinte é um exemplo em Objective-C , implicando que a estrutura OpenStep ou Foundation Kit é usada:

// Classe Foo. 
@interface  Foo  : NSObject
-  ( void ) Olá ;
@fim

// Enviando "hello" para uma instância Foo sem reflexão. 
Foo * obj = [[ Foo alloc ] init ];     
[ obj olá ]; 

// Enviando "hello" para uma instância Foo com reflexão. 
id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ];     
[ obj performSelector : @selector ( hello )];  

Perl

Segue um exemplo em Perl :

# Sem reflexão 
my  $foo  =  Foo -> new ; 
$foo -> olá ;

# ou 
Foo -> new -> olá ;

# Com reflexão 
my  $class  =  "Foo" 
my  $constructor  =  "new" ; 
meu  $método  =  "olá" ;

meu  $f  =  $class -> $construtor ; 
$f -> $método ;

# ou 
$class -> $construtor -> $method ;

# com eval 
eval  "new Foo->hello;" ;

PHP

Segue um exemplo em PHP :

// Sem reflexão 
$foo  =  new  Foo ();


// Com reflexão, usando a API do Reflections 
$reflector  =  new  ReflectionClass ( 'Foo' ); 
$olá = $refletor -> getMethod ( 'olá' ); $olá -> invocar ( $foo );  
  

Python

Segue um exemplo em Python :


olá ()  


# Com reflexão 
obj  =  globals ()[ "Foo" ]() 
getattr ( obj ,  "hello" )()

# Com eval 
eval ( "Foo().hello()" )

R

Segue um exemplo em R :

# Sem reflexão, assumindo que foo() retorna um objeto do tipo S3 que tem o método "hello" 
obj  <-  foo () 
hello ( obj )

# Com reflexão 
class_name  <-  "foo" 
generic_having_foo_method  <-  "hello" 
obj  <-  do.call ( class_name ,  list ()) 
do.call ( generic_having_foo_method ,  alist ( obj ))

Rubi

Segue um exemplo em Ruby :

# Sem reflexão 
obj  =  Foo . novo 
obj . olá

# Com reflexão 
class_name  =  "Foo" 
method_name  =  :hello 
obj  =  Object . const_get ( class_name ) . novo 
obj . enviar  nome_do_método

# Com eval 
eval  "Foo.new.hello"

Xojo

O seguinte é um exemplo usando Xojo :

' Sem reflexão 
Dim  fooInstance  As  New  Foo 
fooInstance . ImprimirOlá

' Com reflexão 
Dim  classInfo  As  Introspection . Typeinfo  =  GetTypeInfo ( Foo ) 
Construtores Dim  () As Introspection . GetConstructors Dim fooInstance As Foo = construtores ( 0 ). Invoque métodos Dim () Como Introspecção . MethodInfo = classInfo . GetMethods for each    
     
     
  m  Como  Introspecção . MethodInfo  Em  métodos 
  Se  m . Nome  =  "PrintHello"  Então 
    m . Invoke ( fooInstance ) 
  End  If 
Next

Veja também

Referências

Citações

  1. ^ Um tutorial sobre reflexão comportamental e sua implementação por Jacques Malenfant et al. (PDF) , desconhecido, arquivado do original (PDF) em 21 de agosto de 2017 , recuperado em 23 de junho de 2019
  2. ^ Brian Cantwell Smith, Procedural Reflection in Programming Languages , Departamento de Engenharia Elétrica e Ciência da Computação, Massachusetts Institute of Technology, tese de doutorado, 1982.
  3. ^ Brian C. Smith. Reflexão e semântica em uma linguagem procedural Arquivado 2015-12-13 na Wayback Machine . Relatório Técnico MIT-LCS-TR-272, Massachusetts Institute of Technology, Cambridge, Massachusetts, janeiro de 1982.
  4. ^ Barros, Paulo; Apenas, René; Millstein, Suzanne; Vinhas, Paulo; Dietl, Werner; d'Amorim, Marcelo; Ernst, Michael D. (agosto de 2015). Análise Estática do Fluxo de Controle Implícito: Resolvendo Java Reflection e Android Intents (PDF) (Relatório). Universidade de Washington. UW-CSE-15-08-01 . Recuperado em 7 de outubro de 2021 .
  5. ^ Eauvidoum, Ieu; ruído do disco (5 de outubro de 2021). "Vinte anos de fuga do Java Sandbox" . Fraque . Vol. 10, não. 46 . Recuperado em 7 de outubro de 2021 .{{cite magazine}}: CS1 maint: uses authors parameter (link)

Fontes

Leitura adicional

  • Ira R. Forman e Nate Forman, Java Reflection in Action (2005), ISBN 1-932394-18-4 
  • Ira R. Forman e Scott Danforth, Colocando Metaclasses para Trabalhar (1999), ISBN 0-201-43305-2 

Links externos