6.5. Introspection
Introspection
is the ability of a program to examine an object's
characteristics, such as its name, parent class (if any), properties,
and methods. With introspection, you can write code that operates on
any class or object. You don't need to know which
methods or properties are defined when you write your code; instead,
you can discover that information at runtime, which makes it possible
for you to write generic debuggers, serializers, profilers, etc. In
this section, we look at the introspective functions provided by PHP.
6.5.1. Examining Classes
To determine
whether a class exists, use the class_exists(
)
function, which takes in a
string and returns a Boolean value. Alternately, you can use the
get_declared_classes(
) function, which returns an
array of defined classes and checks if the class name is in the
returned array:
$yes_no = class_exists(classname);
$classes = get_declared_classes( );
You can get the methods and properties
that exist in a class (including those that are inherited from
superclasses) using the get_class_methods(
) and get_class_vars(
) functions. These functions take a class name and return
an array:
$methods = get_class_methods(classname);
$properties = get_class_vars(classname);
The class name can be a bare word, a quoted string, or a variable
containing the class name:
$class = 'Person';
$methods = get_class_methods($class);
$methods = get_class_methods(Person); // same
$methods = get_class_methods('Person'); // same
The array returned by get_class_methods( ) is a
simple list of method names. The associative array returned by
get_class_vars( ) maps property names to values
and also includes inherited properties. One quirk of
get_class_vars( ) is that it returns only
properties that have default values; there's no way
to discover uninitiailized properties.
Use get_parent_class( ) to find a
class's parent class:
$superclass = get_parent_class(classname);
Example 6-1 lists the display_classes(
)
function,
which displays all currently declared classes and the methods and
properties for each.
Example 6-1. Displaying all declared classes
function display_classes ( ) {
$classes = get_declared_classes( );
foreach($classes as $class) {
echo "Showing information about $class<br />";
echo "$class methods:<br />";
$methods = get_class_methods($class);
if(!count($methods)) {
echo "<i>None</i><br />";
}
else {
foreach($methods as $method) {
echo "<b>$method</b>( )<br />";
}
}
echo "$class properties:<br />";
$properties = get_class_vars($class);
if(!count($properties)) {
echo "<i>None</i><br />";
}
else {
foreach(array_keys($properties) as $property) {
echo "<b>\$$property</b><br />";
}
}
echo "<hr />";
}
}
Figure 6-1 shows the output of the
display_classes( ) function.
Figure 6-1. Output of display_classes( )
6.5.2. Examining an Object
To get the class to which an object belongs,
first make sure it is an object using the is_object(
) function, then get the class with the
get_class( ) function:
$yes_no = is_object(var);
$classname = get_class(object);
Before calling a method on an object, you can ensure that it exists
using the method_exists(
) function:
$yes_no = method_exists(object, method);
Calling an undefined method triggers a runtime exception.
Just as get_class_vars( ) returns an array of
properties for a class, get_object_vars(
)
returns an array of properties set in
an object:
$array = get_object_vars(object);
And just as get_class_vars( ) returns only those
properties with default values, get_object_vars( )
returns only those properties that are set:
class Person {
var $name;
var $age;
}
$fred = new Person;
$fred->name = 'Fred';
$props = get_object_vars($fred); // $props is array('name' => 'Fred');
The get_parent_class(
) function actually accepts
either an object or a class name. It returns the name of the parent
class, or FALSE if there is no parent class:
class A {}
class B extends A {}
$obj = new B;
echo get_parent_class($obj); // prints A
echo get_parent_class(B); // prints A
6.5.3. Sample Introspection Program
Example 6-2 shows a collection of functions that display a
reference page of information about an object's
properties, methods, and inheritance tree.
Example 6-2. Object introspection functions
// return an array of callable methods (include inherited methods)
function get_methods($object) {
$methods = get_class_methods(get_class($object));
if(get_parent_class($object)) {
$parent_methods = get_class_methods(get_parent_class($object));
$methods = array_diff($methods, $parent_methods);
}
return $methods;
}
// return an array of inherited methods
function get_inherited_methods($object) {
$methods = get_class_methods(get_class($object));
if(get_parent_class($object)) {
$parent_methods = get_class_methods(get_parent_class($object));
$methods = array_intersect($methods, $parent_methods);
}
return $methods;
}
// return an array of superclasses
function get_lineage($object) {
if(get_parent_class($object)) {
$parent = get_parent_class($object);
$parent_object = new $parent;
$lineage = get_lineage($parent_object);
$lineage[] = get_class($object);
}
else {
$lineage = array(get_class($object));
}
return $lineage;
}
// return an array of subclasses
function get_child_classes($object) {
$classes = get_declared_classes( );
$children = array( );
foreach($classes as $class) {
if (substr($class, 0, 2) == '_ _') {
continue;
}
$child = new $class;
if(get_parent_class($child) == get_class($object)) {
$children[] = $class;
}
}
return $children;
}
// display information on an object
function print_object_info($object) {
$class = get_class($object);
echo '<h2>Class</h2>';
echo "<p>$class</p>";
echo '<h2>Inheritance</h2>';
echo '<h3>Parents</h3>';
$lineage = get_lineage($object);
array_pop($lineage);
echo count($lineage) ? ('<p>' . join(' -> ', $lineage) . '</p>')
: '<i>None</i>';
echo '<h3>Children</h3>';
$children = get_child_classes($object);
echo '<p>' . (count($children) ? join(', ', $children)
: '<i>None</i>') . '</p>';
echo '<h2>Methods</h2>';
$methods = get_class_methods($class);
$object_methods = get_methods($object);
if(!count($methods)) {
echo "<i>None</i><br />";
}
else {
echo '<p>Inherited methods are in <i>italics</i>.</p>';
foreach($methods as $method) {
echo in_array($method, $object_methods) ? "<b>$method</b>( );<br />"
: "<i>$method</i>( );<br />";
}
}
echo '<h2>Properties</h2>';
$properties = get_class_vars($class);
if(!count($properties)) {
echo "<i>None</i><br />";
}
else {
foreach(array_keys($properties) as $property) {
echo "<b>\$$property</b> = " . $object->$property . '<br />';
}
}
echo '<hr />';
}
Here are some sample classes and objects that exercise the
introspection functions from Example 6-2:
class A {
var $foo = 'foo';
var $bar = 'bar';
var $baz = 17.0;
function first_function( ) { }
function second_function( ) { }
};
class B extends A {
var $quux = false;
function third_function( ) { }
};
class C extends B {
};
$a = new A;
$a->foo = 'sylvie';
$a->bar = 23;
$b = new B;
$b->foo = 'bruno';
$b->quux = true;
$c = new C;
print_object_info($a);
print_object_info($b);
print_object_info($c);
Figure 6-2 shows the
output of this code.
Figure 6-2. Object introspection output
 |  |  | | 6.4. Declaring a Class |  | 6.6. Serialization |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|