stringtranslate.com

Programación reflexiva

En informática , la programación reflexiva o reflexión es la capacidad de un proceso para examinar, introspectar 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 utilizando código automodificable . A medida que la mayor parte de la programación se trasladó 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 incorporada en sus sistemas de tipos. [ cita requerida ]

La tesis doctoral de Brian Cantwell Smith de 1982 introdujo la noción de reflexión computacional en lenguajes de programación procedimental 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 la 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 de entidades.

La reflexión hace que un lenguaje sea más adecuado para el código orientado a redes. Por ejemplo, ayuda a lenguajes como Java a funcionar bien en redes al habilitar bibliotecas para serialización, agrupación y formatos de datos variables. Los lenguajes sin reflexión, como C, deben usar 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 supervisar la ejecución de un conjunto de código y puede modificarse a sí mismo de acuerdo con un objetivo deseado de ese conjunto. Esto se logra normalmente asignando dinámicamente el código del programa en tiempo de ejecución.

En lenguajes de programación orientados a objetos como Java , la reflexión permite la inspección de 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 por ejemplo para la creación/instanciación 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 , se puede utilizar la reflexión para eludir las reglas de accesibilidad de los miembros . En el caso de las propiedades de C#, esto se puede lograr escribiendo directamente en el campo de respaldo (normalmente 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 tanto para archivos internos del proyecto como para bibliotecas externas, como los ensamblados de .NET y los archivos de Java.

Implementación

Un lenguaje que admita la reflexión proporciona una serie de funciones 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 funciones son las siguientes:

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 rellenan varias variables como verb (el nombre del verbo que se llama) y this (el objeto en el que se llama el verbo) para dar el contexto de la llamada. La seguridad se gestiona normalmente accediendo a la pila de llamadas mediante programación: dado que callers () es una lista de los métodos por los que se llamó finalmente al verbo actual, realizar pruebas en callers ()[0] (el comando invocado por el usuario original) permite que el verbo se proteja a sí mismo 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 Objective-C compilado , por ejemplo, registra los nombres de todos los métodos en un bloque del ejecutable, proporcionando una tabla para relacionarlos con los métodos subyacentes (o selectores para estos métodos) compilados en el programa. En un lenguaje compilado que admita 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 utilizando un sistema de transformación de programas para definir cambios automatizados en el código fuente.

Consideraciones de seguridad

La reflexión puede permitir que un usuario cree rutas de flujo de control inesperadas a través de una aplicación, lo que podría eludir las medidas de seguridad. Esto puede ser explotado por atacantes. [4] Las vulnerabilidades históricas en Java causadas por la reflexión insegura permitieron que el código recuperado de máquinas remotas potencialmente no confiables escapara del mecanismo de seguridad de la zona protegida de Java . Un estudio a gran escala de 120 vulnerabilidades de Java 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 la 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 que utiliza el Sistema de objetos Common Lisp :

( defclass foo () ()) ( defmethod print-hello (( f foo )) ( formato T "Hola desde ~S~%" f ))          ;; Normal, sin reflexión ( let (( foo ( make-instance 'foo ))) ( print-hello foo ))     ;; Con la reflexión para buscar la clase llamada "foo" y el método llamado "print-hello" que se especializa en "foo". ( let* (( foo-class ( find-class ( read-from-string "foo" ))) ( print-hello-method ( find-method ( symbol-function ( read-from-string "print-hello" )) nil ( list foo-class )))) ( funcall ( sb-mop:method-generic-function print-hello-method ) ( make-instance foo-class )))                 

DO#

El siguiente es un ejemplo en C# :

// Sin reflexión var foo = new Foo (); foo . PrintHello ();    // Con reflexión Object foo = Activator . CreateInstance ( "complete.classpath.and.Foo" ); MethodInfo método = foo . GetType (). GetMethod ( "PrintHello" ); método . Invoke ( foo , null );       

Delphi, Objeto Pascal

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

utiliza RTTI , Unidad1 ;  procedimiento SinReflexión ; var Foo : TFoo ; comenzar Foo := TFoo . Crear ; intentar Foo . Hola ; finalmente Foo . Libre ; fin ; fin ;           procedimiento WithReflection ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Foo : TObject ; comenzar RttiType := RttiContext . FindType ( 'Unit1.TFoo' ) como TRttiInstanceType ; Foo := RttiType . GetMethod ( 'Create' ) . Invoke ( RttiType . MetaclassType , []) . AsObject ; intentar RttiType . GetMethod ( 'Hello' ) . Invoke ( Foo , []) ; finalmente Foo . Free ; fin ; fin ;                      

CE

El siguiente es un ejemplo en eC:

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

Ir

El siguiente es un ejemplo en Go :

importar "reflejar" // Sin reflexión f := Foo {} f . Hola ()  // Con reflexión fT := reflect . TypeOf ( Foo {}) fV := reflect . New ( fT )    m := fV . MethodByName ( "Hola" ) si m . IsValid () { m . Call ( nulo ) }     

Java

El siguiente es un ejemplo en Java :

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

JavaScript

El siguiente es un ejemplo en JavaScript :

// Sin reflexión const foo = new Foo () foo . hello ()    // Con reflexión const foo = Reflect . construct ( Foo ) const hola = Reflect . get ( foo , 'hola' ) Reflect . apply ( hola , foo , [])         // Con eval eval ( ' new Foo().hello()' )

Julia

El siguiente es un ejemplo en Julia :

julia> struct 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 )   # Acceso con reflexión julia> getfield ( p , :x ) 3  

Objetivo-C

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 ; @end// Enviando "hola" a una instancia de Foo sin reflexión. Foo * obj = [[ Foo alloc ] init ]; [ obj hola ];      // Enviando "hola" a una instancia de Foo con reflexión. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj performSelector : @selector ( hola )];       

Perl

El siguiente es un ejemplo en Perl :

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

PHP

El siguiente es un ejemplo en PHP : [6]

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

Pitón

El siguiente es un ejemplo en Python :

# Sin reflexión obj  =  Foo () obj . hello ()# 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 "hello" obj <- foo () hello ( obj )  # Con reflexión nombre_clase <- "foo" método_genérico_que_tiene_foo <- "hola" obj <- do.call ( nombre_clase , lista ()) do.call ( método_genérico_que_tiene_foo , lista ( ) )        

Rubí

El siguiente es un ejemplo en Ruby :

# Sin reflexión obj = Foo . new obj . hello  # Con reflexión obj = Object . const_get ( "Foo" ) . new obj . send :hello   # Con eval eval "Foo.new.hello" 

Xojo

El siguiente es un ejemplo que utiliza Xojo :

' Sin reflexión Dim fooInstance As New Foo fooInstance . ImprimirHola    ' Con reflexión Dim classInfo As Introspection . Typeinfo = GetTypeInfo ( Foo ) Dim constructores () As Introspection . ConstructorInfo = classInfo . GetConstructors Dim fooInstance As Foo = constructores ( 0 ). Invocar Dim métodos () As Introspection . MethodInfo = classInfo . GetMethods For Each m As Introspection . MethodInfo In métodos If m . Name = "PrintHello" Then m . Invoke ( fooInstance ) End If Next                                  

Véase 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 el 23 de junio de 2019
  2. ^ Brian Cantwell Smith, Reflexión procedimental en lenguajes de programación, Departamento de Ingeniería Eléctrica y Ciencias de la Computación, Instituto Tecnológico 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 Tecnológico de Massachusetts, Cambridge, Massachusetts, enero de 1982.
  4. ^ Barros, Paulo; Just, René; Millstein, Suzanne; Vines, Paul; 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 en Java y las intenciones de Android (PDF) (informe). Universidad de Washington. UW-CSE-15-08-01 . Consultado el 7 de octubre de 2021 .
  5. ^ Eauvidoum, Ieu; disk noise (5 de octubre de 2021). "Veinte años de escapar del entorno de pruebas de Java". Phrack . Vol. 10, núm. 46 . Consultado el 7 de octubre de 2021 .
  6. ^ "PHP: ReflectionClass - Manual". www.php.net .

Fuentes

Lectura adicional

Enlaces externos

Véase también