stringtranslate.com

Programación reflexiva

En informática , la programación reflexiva o reflexión es la capacidad de un proceso de examinar, introspeccionar y modificar su propia estructura y comportamiento. [1]

Antecedentes históricos

Las primeras computadoras se programaron en sus lenguajes ensambladores nativos , que eran inherentemente reflexivos, ya que estas arquitecturas originales podían programarse definiendo instrucciones como datos y usando código automodificable . A medida que la mayor parte de la programación pasó a lenguajes compilados de nivel superior como Algol , Cobol , Fortran , Pascal y C , esta capacidad reflexiva desapareció en gran medida hasta que aparecieron nuevos lenguajes de programación con reflexión integrada en sus sistemas de tipos. [ cita necesaria ]

La tesis doctoral de Brian Cantwell Smith de 1982 introdujo la noción de reflexión computacional en lenguajes de programación procedimentales y la noción del intérprete metacircular como un componente de 3-Lisp. [2] [3]

Usos

Reflection ayuda a los programadores a crear bibliotecas de software genéricas para mostrar datos, procesar diferentes formatos de datos, realizar serialización y deserialización de datos para comunicación, o agrupar y desagregar datos para contenedores o ráfagas de comunicación.

El uso eficaz de la reflexión casi siempre requiere un plan: un marco de diseño, una descripción de codificación, una biblioteca de objetos, un mapa de una base de datos o relaciones entre entidades.

La reflexión crea un lenguaje más adecuado para el código orientado a la red. Por ejemplo, ayuda a lenguajes como Java a funcionar bien en redes al permitir bibliotecas para serialización, agrupación y formatos de datos variables. Los lenguajes sin reflexión, como C, deben utilizar compiladores auxiliares para tareas como la notación de sintaxis abstracta para producir código para serialización y agrupación.

La reflexión se puede utilizar para observar y modificar la ejecución del programa en tiempo de ejecución . Un componente de programa orientado a la reflexión puede monitorear la ejecución de un recinto de código y puede modificarse a sí mismo de acuerdo con el objetivo deseado de ese recinto. Por lo general, esto se logra asignando dinámicamente código de programa en tiempo de ejecución.

En lenguajes de programación orientados a objetos como Java , la reflexión permite inspeccionar clases, interfaces, campos y métodos en tiempo de ejecución sin conocer los nombres de las interfaces, campos y métodos en tiempo de compilación . También permite la creación de instancias de nuevos objetos y la invocación de métodos.

La reflexión se utiliza a menudo como parte de las pruebas de software , como para la creación/creación de instancias en tiempo de ejecución de objetos simulados .

La reflexión también es una estrategia clave para la metaprogramación .

En algunos lenguajes de programación orientados a objetos como C# y Java , la reflexión se puede utilizar para eludir las reglas de accesibilidad de los miembros . Para las propiedades de C#, esto se puede lograr escribiendo directamente en el campo de respaldo (generalmente invisible) de una propiedad no pública. También es posible encontrar métodos no públicos de clases y tipos e invocarlos manualmente. Esto funciona para archivos internos del proyecto, así como para bibliotecas externas como los ensamblados de .NET y los archivos de Java.

Implementación

Un lenguaje que admite la reflexión proporciona una serie de características disponibles en tiempo de ejecución que de otro modo serían difíciles de lograr en un lenguaje de nivel inferior. Algunas de estas características son las capacidades de:

Estas características se pueden implementar de diferentes maneras. En MOO , la reflexión forma una parte natural del lenguaje de programación cotidiano. Cuando se llaman verbos (métodos), se completan varias variables como verb (el nombre del verbo que se llama) y this (el objeto sobre el cual se llama el verbo) para proporcionar el contexto de la llamada. La seguridad generalmente se administra accediendo a la pila de llamadas mediante programación: dado que llamadores () es una lista de los métodos mediante los cuales finalmente se llamó al verbo actual, realizar pruebas en las personas que llaman ()[0] (el comando invocado por el usuario original) permite que verbo protegerse contra el uso no autorizado.

Los lenguajes compilados dependen de su sistema de ejecución para proporcionar información sobre el código fuente. Un ejecutable compilado de Objective-C , por ejemplo, registra los nombres de todos los métodos en un bloque del ejecutable, proporcionando una tabla que los corresponde con los métodos subyacentes (o selectores para estos métodos) compilados en el programa. En un lenguaje compilado que admite la creación de funciones en tiempo de ejecución, como Common Lisp , el entorno de ejecución debe incluir un compilador o un intérprete.

La reflexión se puede implementar para lenguajes sin reflexión incorporada mediante el uso de un sistema de transformación de programas para definir cambios automatizados en el código fuente.

Consideraciones de Seguridad

Reflection puede permitir a un usuario crear rutas de flujo de control inesperadas a través de una aplicación, evitando potencialmente las medidas de seguridad. Esto puede ser aprovechado por los atacantes. [4] Las vulnerabilidades históricas en Java causadas por una reflexión insegura permitieron que el código recuperado de máquinas remotas potencialmente no confiables escapara del mecanismo de seguridad del entorno limitado de Java. Un estudio a gran escala de 120 vulnerabilidades de Java realizado en 2013 concluyó que la reflexión insegura es la vulnerabilidad más común en Java, aunque no la más explotada. [5]

Ejemplos

Los siguientes fragmentos de código crean una instancia foo de clase Foo e invocan su método PrintHello . Para cada lenguaje de programación , se muestran secuencias de llamadas normales y basadas en reflexión.

ceceo común

El siguiente es un ejemplo en Common Lisp utilizando el sistema de objetos Common Lisp :

( defclass foo () ()) ( defmethod print-hello (( f foo )) ( formato T "Hola desde ~S~%" f ))          ;; Normal, sin reflejo ( let (( foo ( make-instance 'foo ))) ( print-hello foo ))     ;; Con reflexión buscar la clase llamada "foo" y el método ;; llamado "print-hello" que se especializa en "foo". ( let* (( foo-class ( buscar-clase ( lectura-de-cadena "foo" ))) ( imprimir-método-hola ( buscar-método ( símbolo-función ( leer-desde-cadena "imprimir-hola" ) ) nil ( lista foo-class )))) ( funcall ( sb-mop: método-función-generica print-hello-method ) ( make-instance foo-class )))                 


C#

El siguiente es un ejemplo en C# :

// Sin reflexión var foo = new Foo (); foo . ImprimirHola ();    // Con reflexión Objeto foo = Activador . CreateInstance ( "completa.classpath.and.Foo" ); Método MethodInfo = foo . Obtener tipo (). GetMethod ( "ImprimirHola" ); método . Invocar ( foo , nulo );       

Delfos, Objeto Pascal

Este ejemplo de Delphi y Object Pascal supone que se ha declarado una clase TFoo en una unidad llamada Unidad1 :

utiliza RTTI , Unidad1 ;  procedimiento SinReflexión ; var Foo : TFoo ; comenzar Foo : = TFoo . Crear ; prueba Foo . Hola ; finalmente Foo . Gratis ; fin ; fin ;           procedimiento ConReflexión ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Foo : TObjeto ; comenzar RttiType : = RttiContext . FindType ( 'Unit1.TFoo' ) como TRttiInstanceType ; Foo := RttiType . GetMethod ( 'Crear' ) . Invocar ( RttiType . MetaclassType , []) . ComoObjeto ; prueba RttiType . GetMethod ( 'Hola' ) . Invocar ( Foo , []) ; finalmente Foo . Gratis ; fin ; fin ;                      

CE

El siguiente es un ejemplo en eC :

// Sin reflexión Foo foo { }; foo . Hola ();   // Con reflexión Clase fooClass = eSystem_FindClass ( __thisModule , "Foo" ); Instancia foo = eInstance_New ( fooClass ); Método m = eClass_FindMethod ( fooClass , "hola" , fooClass . módulo ); (( void ( ) ())( void * ) m . función )( foo );              

Ir

El siguiente es un ejemplo en Go :

importar "reflejar" // Sin reflexión f := Foo {} f . Hola ()  // Con reflexión fT := reflejar . TypeOf ( Foo {}) fV : = reflejar . Nuevo ( pies )    m := fV . MethodByName ( "Hola" ) si m . Es válido () { m . Llamar ( nulo ) }     

Java

El siguiente es un ejemplo en Java :

importar java.lang.reflect.Method ; // Sin reflexión Foo foo = new Foo (); foo . Hola ();    // Con reflexión intenta { Object foo = Foo . clase . getDeclaredConstructor (). nueva instancia ();      Método m = foo . obtenerClase (). getDeclaredMethod ( "hola" , nueva clase <?>[ 0 ] ); m . invocar ( foo ); } captura ( ReflectiveOperationException ignorada ) {}          

javascript

El siguiente es un ejemplo en JavaScript :

// Sin reflexión const foo = new Foo () foo . Hola ()    // Con reflexión const foo = Reflejar . construir ( Foo ) const hola = Reflexionar . get ( foo , 'hola' ) Reflexionar . aplicar ( hola , foo , [])         // Con eval eval ( 'nuevo Foo().hola()' )

Julia

El siguiente es un ejemplo en Julia :

julia> estructura Punto x :: Int y fin     # Inspección con reflexión julia> nombres de campo ( Punto ) (:x, :y) julia> tipos de campo ( Punto ) (Int64, Cualquiera) julia > p = Punto ( 3 , 4 )   #Accede con reflexión julia> getfield ( p , :x ) 3  

C objetivo

El siguiente es un ejemplo en Objective-C , lo que implica que se utiliza el marco OpenStep o Foundation Kit :

// clase Foo. @interface  Foo  : NSObject -  ( void ) hola ; @fin// Envío de "hola" a una instancia de Foo sin reflexión. Foo * obj = [[ Foo alloc ] init ]; [ obj hola ];      // Envío de "hola" a una instancia de Foo con reflexión. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj performSelector : @selector ( hola )];       

perla

El siguiente es un ejemplo en Perl :

# Sin reflexión my $foo = Foo -> new ; $foo -> hola ;   # o Foo -> nuevo -> hola ;# Con reflexión my $class = "Foo" my $constructor = "new" ; mi $metodo = "hola" ;         mi $f = $clase -> $constructor ; $f -> $método ;   # o $clase -> $constructor -> $método ;# con eval eval "nuevo Foo->hola;" ; 

PHP

El siguiente es un ejemplo en PHP : [6]

// Sin reflexión $foo  =  new  Foo (); $foo -> hola ();// Con reflexión, usando la API de Reflections $reflector  =  new  ReflectionClass ( "Foo" ); $foo  =  $reflector -> nuevaInstancia (); $hola  =  $reflector -> getMethod ( "hola" ); $hola -> invocar ( $foo );

Pitón

El siguiente es un ejemplo en Python :

# Sin reflexión obj  =  Foo () obj . Hola ()# Con reflexión obj  =  globals ()[ "Foo" ]() getattr ( obj ,  "hola" )()# Con eval eval ( "Foo().hello()" )

R

El siguiente es un ejemplo en R :

# Sin reflexión, suponiendo que foo() devuelve un objeto de tipo S3 que tiene el método "hola" obj <- foo () hola ( obj )  # Con reflexión nombre_clase <- "foo" generic_having_foo_method <- "hola" obj <- do.call ( class_name , list ()) do.call ( generic_having_foo_method , alist ( obj ))        

Rubí

El siguiente es un ejemplo en Ruby :

# Sin reflexión obj = Foo . nuevo objeto . Hola  # Con reflexión obj = Objeto . const_get ( "Foo" ) . nuevo objeto . enviar : hola   # Con eval eval "Foo.new.hello" 

Xojo

El siguiente es un ejemplo usando Xojo :

' Sin reflexión Dim fooInstance As New Foo fooInstance . ImprimirHola    ' Con reflexión Dim classInfo como introspección . Typeinfo = GetTypeInfo ( Foo ) Constructores tenues () Como introspección . ConstructorInfo = información de clase . GetConstructors Dim fooInstance As Foo = constructores ( 0 ). Invocar métodos Dim () como introspección . InformaciónMétodo = informaciónclase . GetMethods para cada m como introspección . MethodInfo En métodos Si m . Nombre = "ImprimirHola" Luego m . Invocar ( fooInstance ) Finalizar si es el siguiente                                  

Ver también

Referencias

Citas

  1. ^ Un tutorial sobre la reflexión conductual y su implementación por Jacques Malenfant et al. (PDF) , desconocido, archivado desde el original (PDF) el 21 de agosto de 2017 , recuperado 23 de junio de 2019
  2. ^ Brian Cantwell Smith, Reflexión procesal en lenguajes de programación, Departamento de Ingeniería Eléctrica e Informática, Instituto de Tecnología de Massachusetts, tesis doctoral, 1982.
  3. ^ Brian C. Smith. Reflexión y semántica en un lenguaje procedimental Archivado el 13 de diciembre de 2015 en Wayback Machine . Informe técnico MIT-LCS-TR-272, Instituto de Tecnología de Massachusetts, Cambridge, Massachusetts, enero de 1982.
  4. ^ Barros, Paulo; Justo, René; Millstein, Suzanne; Vides, Pablo; Dietl, Werner; d'Amorim, Marcelo; Ernst, Michael D. (agosto de 2015). Análisis estático del flujo de control implícito: resolución de la reflexión de Java y las intenciones de Android (PDF) (Reporte). Universidad de Washington. UW-CSE-15-08-01 . Consultado el 7 de octubre de 2021 .
  5. ^ Eauvidoum, Ieu; ruido del disco (5 de octubre de 2021). "Veinte años escapando del entorno limitado de Java". Phrack . vol. 10, núm. 46 . Consultado el 7 de octubre de 2021 .
  6. ^ "PHP: Clase de reflexión - Manual". www.php.net .

Fuentes

Otras lecturas

enlaces externos