Recipe 7.19. Introspecting Objects

7.19.1. Problem

You want to inspect an object to see what methods and properties it has, which lets you write code that works on any generic object, regardless of type.

7.19.2. Solution

Use the Reflection classes to probe an object for information.

For a quick overview of the class, call Reflection::export( ):

// learn about cars Reflection::export(new ReflectionClass('car'));

Or probe for specific data:

$car = new ReflectionClass('car'); if ($car->hasMethod('retractTop')) {     // car is a convertible }

7.19.3. Discussion

It's rare to have an object and be unable to examine the actual code to see how it's described. Still, with the Reflection classes, you can programmatically extract information about both object-oriented features, such as classes, methods, and properties, but also non-OO features, such as functions and extensions.

This is useful for projects you want to apply to a whole range of different classes, such as creating automated class documentation, generic object debuggers, and state savers, like serialize( ).

To help show how the Reflection classes work, Example 7-39 contains an example Person class that uses many of PHP 5's OO features.

Person class

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.

Example 7-40 shows a short command-line script that searches for the filename and starting line number of a method or function.

Using reflection to locate function and method definitions

<?php if ($argc < 2) {     print "$argv[0]: function/method, classes1.php [, ... classesN.php]\n";     exit; } // Grab the function name $function = $argv[1]; // Include the files foreach (array_slice($argv, 2) as $filename) {     include_once $filename; } try {     if (strpos($function, '::')) {         // It's a method         list ($class, $method) = explode('::', $function);         $reflect = new ReflectionMethod($class, $method);     } else {         // It's a function         $reflect = new ReflectionFunction($function);     }     $file = $reflect->getFileName();     $line = $reflect->getStartLine();     printf ("%s | %s | %d\n", "$function()", $file, $line); } catch (ReflectionException $e) {     printf ("%s not found.\n", "$function()"); } ?>

Pass the function or method name as the first argument, and the include files as the remaining arguments. These files are then included, so make sure they don't print out anything.

The next step is to determine whether the first argument is a method or a function. Since methods are in the form class::method, you can use strpos( ) to tell them apart.

If it's a method, use explode( ) to separate the class from the method, passing both to ReflectionMethod. If it's a function, you can directly instantiate a ReflectionFunction without any difficulty.

Since ReflectionMethod extends ReflectionFunction, you can then call both getFileName( ) and getStartLine( ) of either class. This gathers the information that you need to print out, which is done via printf( ).

When you try to instantiate a ReflectionMethod or ReflectionFunction with the name of an undefined method, these classes throw a ReflectionException. Here, it's caught and an error message is displayed.

A more complex script that prints out the same type of information for all user-defined methods and functions appears in Recipe 7.23.

If you just need a quick view at an object instance, and don't want to fiddle with the Reflection classes, use either var_dump( ), var_export( ), or print_r( ) to print the object's values. Each of these three functions prints out information in a slightly different way; var_export( ) can optionally return the information, instead of displaying it.

7.19.4. See Also

Recipe 5.8 for more on printing variables; documentation on Reflection at, var_dump( ) at, var_export( ) at, and print_r( ) at .

PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445 © 2008-2017.
If you may any questions please contact us: