Extended Reflection API
Introduction
The main objective of the Extended Reflection API is to enhance PHP by type information and annotations. Source code documentations often provide information which fulfils very similar purposes. But most times these documentations are not formal and only understandable by human beings. In the PHP world there is a tool called phpDocumentor/PHPDoc which provides a common way to document source code and uses a formal schema which can be processed by a computer.
The Extended Reflection API uses the source code documentation to determine type information and any other information provided via so called doc-tags. Those tags can be used to realise systems which depend on strong type information or additional information to the source code itself. Application scenarios are WSDL generation for Web Services or Aspect-Oriented Programming. Processable additions to the source code in general enable a wide range of new applications.
Reflection API
Since PHP5 a Reflection API has been included in the standard PHP distribution. It provides an API to get information about classes and all there methods and properties, without the need to parse any source code. Simple functions, runtime objects and PHP Extensions can be inspected, too. But information gathering is not the only feature. It is also possible to modify properties of objects, invoke arbitrary methods/functions and instantiate objects with this Reflection API. With PHP5.1 its capabilities had been enhanced to fulfil all requirements of the Extended Reflection API and it is possible to extract all comments associated to a language construct with API methods at runtime.
Fig. 1. PHP5 Reflection API
As shown in Fig. 1 the Reflection API conforms to the meta model of an object-oriented programming language. So it is possible to reflect all aspects of a given class or object.
Extended Reflection API
The Reflection API itself is implemented as a extension written in C for maximum performance and conceptual reasons. The Extended Reflection API is based on this extension and all elements are derived from the given base classes. Therefore, it has the same features, power and performance as the original Reflection API only enhanced by the ability to obtain annotations for classes, functions/methods or properties. This new feature is also used to implement a type system which enables a script to obtain information about the types of parameters, return values and properties. But this requires a correct source code documentation and does not enforce any constraints at runtime. The PHP language runtime is not modified at all. So it is possible that runtime behaviour does not correspond with expected behaviour caused by improper documentation.
Fig. 2. Extended Reflection API and Type System
In Fig. 2 the Extended Reflection API is shown. For all classes in the Reflection API new subclasses are introduced, which provide new implementations of the inherited methods and additional methods to access type information and annotations. In addition a new class called ExtendedReflectionAPI is defined, which provides methods necessary to generate Reflection Objects e.g. like getTypeByName. This method will return the appropriate type object for a given type name. For extensibility it is possible to set a different Factory for Type Objects, too. This may be used to extend the provided type system with additional features. Currently it is used for proper type mapping using type names as strings.
The type system is designed to distinguish between three main types. PrimitiveTypes are all build in types like Integer, Float, String and so on. ArrayTypes are all kinds of arrays and ClassTypes are used to reflect user defined classes. This differentiation has been made in consideration of the language behaviour and the capabilities of WSDL for defining types in a language independent way. As arrays are treated in a special way they are additionally classified in simple arrays and maps. Maps are used if the array is an associative array and it is used much like key, value pairs.
API Definitions
<?php class ExtendedReflectionApi { public static ExtendedReflectionApi getInstance() public void setTypeFactory(TypeFactory $factory) public Type getTypeByName(string $typeName) } ?>
This global singleton acts as central entry point and factory for reflection by type name. Therefore, it is possible to set a new type factory which could provide enhanced features. If none is provided the standard TypeFactoryImpl is used.
<?php interface Type { function Type getArrayType(); function Type getMapIndexType(); function Type getMapValueType(); function boolean isArray(); function boolean isClass(); function boolean isPrimitive(); function boolean isMap(); function string toString(); function boolean isStandardType(); function string getXmlName(); function DOMElement getXmlSchema(DOMDocument $dom); } ?>
The Type interface acts as a central interface for the type system. It is equipped with several methods to reflect attributes about a type. For convenience and usability also methods for an XML Schema mapping are incorporated at this point.
<?php class ClassType extends ExtReflectionClass implements Type { public Type getArrayType() public Type getMapIndexType() public Type getMapValueType() public boolean isArray() public boolean isClass() public boolean isPrimitive() public boolean isMap() public string toString() public boolean isStandardType() public string getXmlName(boolean $usePrefix) public DOMElement getXmlSchema(DOMDocument $dom, $namespaceXSD) public void __construct(string $name) } ?>
ClassType is one incarnation of the Type interface. ArrayType and PrimitiveType behave similar and are not discussed at this point. Unlike ArrayType and PrimitiveType, the ClassType is tightly integrated with the Extended Reflection API and extends ExtRefelectionClass to inherit all its capabilities.
<?php class ExtReflectionClass extends ReflectionClass { public void __construct(string $name) public ExtReflectionMethod getMethod(string $name) public ExtReflectionMethod getConstructor() public ExtReflectionMethod[] getMethods() public ClassType getParentClass() public ExtReflectionProperty getProperty(string $name) public ExtReflectionProperty[] getProperties() public boolean isWebService() public string getShortDescription() public string getLongDescription() public boolean isTagged(string $with) public PHPDocTag[] getTags(string $name) public ExtReflectionExtension getExtension() } ?>
ExtReflectionClass inherits from the ReflectionClass and redefines all methods which return a reflection object to return objects from the Extended Reflection API. In addition methods for annotation handling are introduced e.g. getTags, isTagged etc. The general getDocComment method had been superseded by getShortDescription and getLongDescription. This methods return only the part of interest in a PHPDoc comment.
The following classes are analogue to ExtReflectionClass enhancements to the Reflection API and behave very similar.
<?php class ExtReflectionExtension extends ReflectionExtension { public void __construct(string $name) public ExtReflectionFunction[] getFunctions() public ExtReflectionClass[] getClasses() } class ExtReflectionFunction extends ReflectionFunction { public void __construct(string $name) public ExtReflectionParameter[] getParameters() public Type getReturnType() public string getReturnDescription() public boolean isWebmethod() public string getShortDescription() public string getLongDescription() public boolean isTagged(string $with) public PHPDocTag[] getTags(string $name) } class ExtReflectionMethod extends ReflectionMethod { public void __construct(mixed $class, string $name) public ExtReflectionParameter[] getParameters() public Type getReturnType() public string getReturnDescription() public boolean isWebmethod() public string getShortDescription() public string getLongDescription() public boolean isTagged(string $with) public PHPDocTag[] getTags(string $name) public boolean isMagic() public ClassType getDeclaringClass() } class ExtReflectionParameter extends ReflectionParameter { public void __construct(mixed $mixed, mixed $parameter) public Type getType() public ClassType getClass() public ExtReflectionFunction getDeclaringFunction() public ClassType getDeclaringClass() } class ExtReflectionProperty extends ReflectionProperty { public void __construct(mixed $class, string $name) public Type getType() public ClassType getDeclaringClass() } ?>
Links to their code files
- ExtReflectionExtension
- ExtReflectionFunction
- ExtReflectionMethod
- ExtReflectionParameter
- ExtReflectionProperty
TODO
- Tutorials
- how to use the type system
- how to get information about a class
- how to extend the Extended Reflection API