Skip to content
Alex Kiesel edited this page Jun 7, 2012 · 7 revisions

Reflection

The XP framework offers its own reflection API.

Classes

The most common entry point is the lang.XPClass class. Instances of it can be retrieved by either using its static forName() method or by calling the instance method getClass() on any object.

<?php
  $class= XPClass::forName('util.collections.HashTable');
  $class= create(new HashTable())->getClass();
?>

Hint: To retrieve an object's class name, you can either use $object->getClass()->getName()` or the shortcut `$object->getClassName(). The latter is not only shorter but also significantly faster!

With the XPClass instance in the $class variable, one has access to all features of a class:

Methods --- Via `getMethods()`, `getMethod()` and `hasMethod()` accessors.
<?php
  $method= $class->getMethod('toString');
?>

The returned lang.reflect.Method instance offers access to:

  • Parameters - via getParameters()
  • Return type - via getReturnType()
  • Thrown exceptions - via getExceptionTypes()
  • Annotations - via getAnnotations()
  • Modifiers - via getModifiers()

...and provides means to invoke the method:

<?php
  with ($class= XPClass::forName('util.log.Logger')); {
    $log= $class->getMethod('getInstance')->invoke(NULL);   // Static
    $str= $class->getMethod('toString')->invoke($log);      // Instance
  }
?>
Constructor --- Via `getConstructor()` and `hasConstructor()` accessors.
<?php
  $constructor= $class->getConstructor();
?>

The returned lang.reflect.Constructor instance offers access to:

  • Parameters - via getParameters()
  • Thrown exceptions - via getExceptionTypes()
  • Annotations - via getAnnotations()
  • Modifiers - via getModifiers()

...and provides means to invoke it:

<?php
  with ($class= XPClass::forName('util.Binford')); {
    $binford6100= $class->getConstructor()->invoke(array(6100));
  }
?>
Fields --- Via `getFields()`, `getField()` and `hasField()` accessors.
<?php
  $field= $class->getField('elements');
?>

The returned lang.reflect.Field instance offers access to:

  • Type - via getType()
  • Modifiers - via getModifiers()

...and provides means to read its value:

<?php
  with ($class= XPClass::forName('util.Binford')); {
    $power= $class->getField('poweredBy')->get(new Binford(6100));
  }
?>
Annotations --- Via `getAnnotations()`, `getAnnotation()` and `hasAnnotation()` accessors.
<?php
  #[@bean(name= 'contract/history/1.0')]
  class HistoryBean extends Object {
  
  }
  
  $name= XPClass::forName('HistoryBean')->getAnnotation('bean', 'name');
?>

See also the Annotations documentation.

Packages

Every class resides inside a package. The lang.reflect.Package class offers methods to reflectively access a package. Instances of it can be retrieved by Package::forName() or by calling the getPackage() on an XPClass instance.

<?php
  $package= Package::forName('util.collections');
  $package= create(new HashTable())->getClass()->getPackage();
?>

Packages are primarily used to load classes and resources:

<?php
  $package= Package::forName('de.thekid.dialog.scriptlet.state');
  $stateName= ucfirst($request->getURL()->getPath());
  
  try {
    $state= $package->loadClass($stateName.'State')->newInstance();
  } catch (ClassNotFoundException $e) {
    throw new HttpScriptletException('File not found', HTTP_NOT_FOUND, $e);
  }
?>

The nice thing about this piece of code is that it will not let users inject arbitrary class names but will throw an lang.IllegalArgumentException in case a class outside of the given package.

To retrieve a config.ini inside the same directory as the class containing the sourcecode one can use the following:

<?php
  $prop= Properties::fromString($this->getClass()
    ->getPackage()
    ->getResource('config.ini')
  );
?>
Clone this wiki locally