The Reflection classes allow you to retrieve detailed data about classes. Although you don't need to use them in most web applications, they're invaluable when you're writing a program such as a class documenter, unit tester, or debugger. These applications all require generic class-manipulation routines.
PHP 4 lets you discover information about classes using a series of functions. There's get_class_methods( ) to get an array of class methods and get_class_vars( ) for an array of properties. These functions aren't integrated, so you cannot find out all the information about a class at once.
The functions are also very simplistic. They don't contain any of the new information that you can set in PHP 5. For example, there's no way to distinguish between private, protected, and public methods and properties.
That's where the Reflection classes come in. They help you extract from a class or method any piece of data you need.
To understand how the Reflection classes work, Example 9-10 contains an example Person class that uses many of PHP 5's OO features.
class Person { public $name; protected $spouse; private $password; public function _ _construct($name) { $this->name = $name } public function getName( ) { return $name; } protected function setSpouse(Person $spouse) { if (!isset($this->spouse)) { $this->spouse = $spouse; } } private function setPassword($password) { $this->password = $password; } }
For a quick overview of the class, call Reflection::export( ):
Reflection::export(new ReflectionClass('Person')); Class [ <user> class Person ] { @@ /www/reflection.php 3-25 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [3] { Property [ <default> public $name ] Property [ <default> protected $spouse ] Property [ <default> private $password ] } - Methods [4] { Method [ <user> <ctor> public method _ _construct ] { @@ /www/reflection.php 8 - 10 - Parameters [1] { Parameter #0 [ $name ] } } Method [ <user> public method getName ] { @@ /www/reflection.php 12 - 14 } Method [ <user> protected method setSpouse ] { @@ /www/reflection.php 16 - 20 - Parameters [1] { Parameter #0 [ Person or NULL $spouse ] } } Method [ <user> private method setPassword ] { @@ /www/reflection.php 22 - 24 - Parameters [1] { Parameter #0 [ $password ] } } } }
The Reflection::export( ) static method takes an instance of the ReflectionClass class and returns a copious amount of information. As you can see, it details the number of constants, static properties, static methods, properties, and methods in the class. Each item is broken down into component parts. For instance, all the entries contain visibility identifiers (private, protected, or public), and methods have a list of their parameters underneath their definition.
Reflection::export( ) not only reports the file where everything is defined, but even gives the line numbers! This lets you extract code from a file and place it in your documentation.
Reflection::export( ) is a handy way to see everything about a class at once, but it's not a very useful method of extracting specific pieces of information.
That's where the individual Reflection classes come in. There's a Reflection class for every major entity in PHP: classes, functions, methods, parameters, properties, and even extensions. Instances of these classes have methods that you can query to determine whether a class is abstract, a method is final, or a property is private. For example:
$class = new ReflectionClass('Person'); if ($class->isAbstract( )) { // Person is abstract } $method = new ReflectionMethod('Person', 'getName'); if ($method->isFinal( )) { // Person::getName( ) is final } $property = new ReflectionProperty('Person', 'name'); if ($property->isPrivate( )) { // Person::name is private }
To inspect a class, create a new ReflectionClass, passing the class name to the constructor. You can query the returned object using any of the methods listed in the next section in Table 9-3.
The ReflectionMethod and ReflectionProperty classes operate similarly, except that they take two arguments. The first argument is still the class name, and the second is the method or property name. Table 9-5 has a list of all the ReflectionMethod methods, and Table 9-6 covers ReflectionProperty.
While it's somewhat useful to check specific methods or properties, the utility of the Reflection classes shines through when they're used in conjunction with each other. For instance, you want to create API documentation for your classes. However, you only want to document public methods because private and protected methods are reserved for internal use. Example 9-11 shows how to do this, using the Person class in Example 9-10 as a base.
$class = new ReflectionClass('Person'); foreach ($class->getMethods( ) as $method) { if ($method->isPublic( )) { print $method->getName( ) . "( )\n"; } } _ _construct( ) getName( )
The getMethods( ) method in Example 9-11 returns an array containing all the methods in the class. The elements of the array are ReflectionMethod( ) objects.
A ReflectionMethod object can be intraspected similarly to a ReflectionClass. Therefore, you can call isPublic( ) to discover whether a method is declared public. If it is, the example uses getName( ) to retrieve its name and prints it out.
You can use another class, ReflectionParameter, to add further detail to your documentation, as in Example 9-12.
$class = new ReflectionClass('Person'); foreach ($class->getMethods( ) as $method) { if ($method->isPublic( )) { print $method->getName( ) . '('; $params = ''; foreach($method->getParameters( ) as $parameter) { $params .= '$' . $parameter->getName( ) . ', '; } print substr($params, 0, -2) . ")\n"; } }
Now you can also list method parameters:
_ _construct($name) getName( )
The ReflectionParameter methods appear in Table 9-7.
This section provides a complete listing of every method in all six of the Reflection classes. Each entry in Tables Table 9-3 through Table 9-8 details what parameters a method takes and what types of values it returns.
There are just over 100 methods in total, but the number of unique methods is almost half of that. As you can see, there's a lot of duplication. For example, classes, methods, and properties can all be declared public; therefore, the ReflectionClass, ReflectionMethod, and ReflectionProperty classes all have an isPublic( ) method.
The method names are largely self-explanatory, but here's a quick overview that explains the naming and behavior patterns.
All of the methods beginning with get retrieve values or objects. For instance, getName( ) returns the object's name.
Some get methods return an array of objects, such as getMethods( ), which returns an array of ReflectionMethods. These methods are marked with square array brackets ([ ]), like ReflectionMethod[ ].
If a method begins with is, it returns a boolean value: either true or false.
One method different from the rest is invoke( ). This method is similar to call_user_func( ), as it lets you pass arguments to a method or function. For example:
function add($i, $j) { return $i + $j; } $math = new ReflectionFunction('add'); print $math->invoke(1, 2); 3
While it makes little sense to create a ReflectionFunction just to call invoke( ), it's handy when you're using the Reflection classes to automate the processing of class methods. One example program is a unit testing application that takes an object and runs all methods beginning with the word test.
Name |
Returns |
---|---|
ReflectionClass::_ _construct(mixed argument) throws ReflectionException |
ReflectionClass |
ReflectionClass::_ _toString( ) |
string |
ReflectionClass::export(mixed argument, [, bool return]) throws ReflectionException |
mixed |
ReflectionClass::getConstant(string name) |
mixed |
ReflectionClass::getConstants( ) |
array |
ReflectionClass::getConstructor( ) |
ReflectionMethod |
ReflectionClass ReflectionProperty::getDeclaringClass( ) |
ReflectionClass |
ReflectionClass::getDefaultProperties( ) |
array |
ReflectionClass::getDocComment( ) |
string |
ReflectionClass::getEndLine( ) |
int |
ReflectionClass::getExtension( ) |
ReflectionExtension or NULL |
ReflectionClass::getExtensionName( ) |
string or false |
ReflectionClass::getFileName( ) |
string |
ReflectionClass::getInterfaces( ) |
ReflectionClass[ ] |
ReflectionClass::getMethod(string name) |
ReflectionMethod |
ReflectionClass::getMethods( ) |
ReflectionMethod[ ] |
ReflectionClass::getModifiers( ) |
int |
ReflectionClass::getName( ) |
string |
ReflectionClass::getParentClass( ) |
ReflectionClass |
ReflectionClass::getProperties( ) |
ReflectionProperty[ ] |
ReflectionClass::getProperty(string name) |
ReflectionProperty |
ReflectionClass::getStartLine( ) |
int |
ReflectionClass::getStaticProperties( ) |
array |
ReflectionClass::implementsInterface(string or ReflectionClass interface_name) |
boolean |
ReflectionClass::isAbstract( ) |
boolean |
ReflectionClass::isFinal( ) |
boolean |
ReflectionClass::isInstance(object) |
boolean |
ReflectionClass::isInstantiable( ) |
boolean |
ReflectionClass::isInterface( ) |
boolean |
ReflectionClass::isInternal( ) |
boolean |
ReflectionClass::isIterateable( ) |
boolean |
ReflectionClass::isSubclassOf(string or ReflectionClass class) |
boolean |
ReflectionClass::isUserDefined( ) |
boolean |
ReflectionClass::newInstance(mixed args) |
object |
Name |
Returns |
---|---|
ReflectionFunction::_ _construct(string name) |
ReflectionFunction |
ReflectionFunction::_ _toString( ) |
string |
ReflectionFunction::export(string name, [, bool return]) throws Reflection_Exception |
mixed |
ReflectionFunction::getDocComment( ) |
string |
ReflectionFunction::getEndLine( ) |
int |
ReflectionFunction::getFileName( ) |
string |
ReflectionFunction::getName( ) |
string |
ReflectionFunction::getParameters( ) |
Reflection_Parameter[ ] |
ReflectionFunction::getStartLine( ) |
int |
ReflectionFunction::getStaticVariables( ) |
array |
ReflectionFunction::invoke(mixed args) |
mixed |
ReflectionFunction::isInternal( ) |
bool |
ReflectionFunction::isUserDefined( ) |
bool |
ReflectionFunction::returnsReference( ) |
bool |
Name |
Returns |
---|---|
ReflectionMethod::_ _construct(mixed class, string name) |
ReflectionMethod |
ReflectionMethod::_ _toString( ) |
string |
ReflectionMethod::export(mixed class, string name, [, bool return]) throws Reflection_Exception |
mixed |
ReflectionMethod::getDeclaringClass( ) |
Reflection_Class |
ReflectionMethod::getDocComment( ) |
string |
ReflectionMethod::getEndLine( ) |
int |
ReflectionMethod::getFileName( ) |
string |
ReflectionMethod::getModifiers( ) |
int |
ReflectionMethod::getName( ) |
string |
ReflectionMethod::getParameters( ) |
Reflection_Parameter[ ] |
ReflectionMethod::getStartLine( ) |
int |
ReflectionMethod::getStaticVariables( ) |
array |
ReflectionMethod::invoke(mixed object, mixed args) |
mixed |
ReflectionMethod::isAbstract( ) |
boolean |
ReflectionMethod::isConstructor( ) |
boolean |
ReflectionMethod::isDestructor( ) |
boolean |
ReflectionMethod::isFinal( ) |
boolean |
ReflectionMethod::isInternal( ) |
boolean |
ReflectionMethod::isPrivate( ) |
boolean |
ReflectionMethod::isProtected( ) |
boolean |
ReflectionMethod::isPublic( ) |
boolean |
ReflectionMethod::isStatic( ) |
boolean |
ReflectionMethod::isUserDefined( ) |
boolean |
ReflectionMethod::returnsReference( ) |
boolean |
Name |
Returns |
---|---|
ReflectionProperty::_ _construct(mixed class, string name) |
ReflectionProperty |
ReflectionProperty::_ _toString( ) |
string |
ReflectionProperty::export(mixed class, string name, [, bool return]) throws Reflection_Exception |
mixed |
ReflectionProperty::getDeclaringClass( ) |
Reflection_Class |
ReflectionProperty::getModifiers( ) |
int |
ReflectionProperty::getName( ) |
string |
ReflectionProperty::getValue(object object) |
mixed |
ReflectionProperty::isDefault( ) |
boolean |
ReflectionProperty::isPrivate( ) |
boolean |
ReflectionProperty::isProtected( ) |
boolean |
ReflectionProperty::isPublic( ) |
boolean |
ReflectionProperty::isStatic( ) |
boolean |
ReflectionProperty::setValue(object object, mixed value) |
void |
Name |
Returns |
---|---|
ReflectionParameter::_ _construct(mixed function, mixed parameter) |
ReflectionParameter |
ReflectionParameter::_ _toString( ) |
string |
ReflectionParameter::allowsNull( ) |
boolean |
ReflectionParameter::export(mixed function, mixed parameter, [, bool return]) throws Reflection_Exception |
mixed |
ReflectionParameter::getClass( ) |
string |
ReflectionParameter::getName( ) |
string |
ReflectionParameter::isPassedByReference( ) |
boolean |
Name |
Returns |
---|---|
ReflectionExtension::_ _construct(string name) |
ReflectionExtension |
ReflectionExtension::_ _toString( ) |
string |
ReflectionExtension::export(string name, [, bool return]) throws Reflection_Exception |
mixed |
ReflectionExtension::getClasses( ) |
Reflection_Class[ ] |
ReflectionExtension::getClassNames( ) |
array |
ReflectionExtension::getConstants( ) |
array |
ReflectionExtension::getFunctions( ) |
Reflection_Function[ ] |
ReflectionExtension::getINIEntries( ) |
array |
ReflectionExtension::getName( ) |
string |
ReflectionExtension::getVersion( ) |
string |