devxlogo

Taking Advantage of the New Reflection API in PHP5

Taking Advantage of the New Reflection API in PHP5

f you haven’t yet upgraded from PHP4 to PHP5, this article will give you a serious reason to do so: PHP5 now supports reflection through the Reflection API, which you can use to examine variables, interfaces, functions, methods, parameters, classes—and more. The Reflection API is generous; it offers a large number of classes and methods that you can use to accomplish reflection tasks.

To get a sense of the the theoretical aspect of the Reflection API, you’ll see a brief description of the Reflection API classes and methods, illustrated by short examples. Later, you’ll see two real-world application examples in PHP that make run-time decisions about which methods to call and auto-generate well-formatted HTML documentation for your PHP classes.

Reflection API Classes and Methods

 
Figure 1. Reflection API Classes: Here are the relationships between the Reflection API classes and methods.

As a quick overview of the Reflection API’s capabilities, here’s a diagram (see Figure 1) that presents the Reflection API classes/methods and the relationships between them. Notice that all the Reflection API classes implement the Reflector interface except for Reflection, ReflectionException, and ReflectionFunctionAbstract. All exportable Reflection classes implement the Reflector interface.

The ReflectionClass
You can think of the ReflectionClass class as the main class of the Reflection API. You use it to apply reflection over other classes, extracting timely information about all class components. I’ll show you a few examples of using ReflectionClass methods and then just list the calls and descriptions for the rest, because they’re all similar.

  • public void construct(string name)—This is the ReflectionClass constructor.
  • public string getName()—This method returns the inspected class name.
   // EXAMPLE   $class = new ReflectionClass('TestClass');   echo "The class name: ".$class->getName();
  • public ReflectionMethod getConstructor()—This method returns a ReflectionMethod object that represents the introspected class constructor.
   // EXAMPLE   $class = new ReflectionClass('TestClass');   $constructor = $class->getConstructor();   echo $constructor;
  • public ReflectionMethod getMethod(string name)—This method returns a ReflectionMethod object representing the method specified by the name parameter.
   // EXAMPLE   $class = new ReflectionClass('TestClass');   $method = $class->getMethod('testMethod_1');   echo $method;
  • public ReflectionMethod[] getMethods()—Returns an array of RelectionMethod objects containing all the introspected class methods.
   // EXAMPLE   $class = new ReflectionClass('TestClass');   $methods = $class->getMethods();   foreach($methods as $in)      { echo $in; }

In addition to the methods already listed, the class exposes similar methods that you use in the same way: You create a ReflectionClass instance, passing the name of the class you want to inspect as a parameter, and then use that instance to call the methods below:

  • public ReflectionProperty getProperty(string name)
  • public ReflectionProperty[] getProperties()
  • public mixed getConstant(string name)
  • public array getConstants()
  • public ReflectionClass[] getInterfaces()
See also  Custom Java Web Development - The Heartbeat of Modern Web Development

The objects you retrieve using the preceding methods give you access to “deeper” levels of information in the class, as described in the next section.

The ReflectionMethod, ReflectionProperty, and ReflectionFunction Classes
You use the ReflectionMethod class to apply reflection to methods to obtain specific information about an introspected method. Again, I’ll provide a few examples and a list of similar methods:

  • public void __construct(mixed class, string name)—This is the ReflectionMethod constructor.
  • public mixed invoke(stdclass object [, mixed args [, …]])—Use this to call an introspected method.
   // EXAMPLES   //call a non-static method with no arguments   $testClass = new TestClass();   $method = new ReflectionMethod('TestClass', 'testMethod_1');   echo $method->invoke($testClass);      //call a non-static method with two arguments   $testClass = new TestClass();   $method = new ReflectionMethod('TestClass', 'testMethod_2');   echo $method->invoke($testClass, 'testValue_1', 'testValue_2');      //call a static method with no arguments   $method = new ReflectionMethod('TestClass', 'testMethod_3');   echo $method->invoke(NULL);      //call a static method with two arguments   $method = new ReflectionMethod('TestClass', 'testMethod_4');   echo $method->invoke(NULL,'testValue_1','testValue_2');

Some other available methods are:

  • public bool isPublic()—Returns a Boolean true if the introspected method is public.
  • public bool isPrivate()—Returns a Boolean true if the introspected method is private.
  • public bool isProtected()—Returns a Boolean true if the introspected method is protected.
   // EXAMPLE   $method = new ReflectionMethod('TestClass', 'testMethod_1');   echo $method->isPublic();

Just as you use the ReflectionMethod class to apply reflection to methods, you use the ReflectionProperty class to apply reflection to properties. The methods of this class are nearly identical to the ReflectionMethod class methods, so I’ll show only a minimal set of examples here. To construct a ReflectionProperty object use:

   public void __construct(mixed class, string name)

To get a property’s value, use:

   public mixed getValue(stdclass object): 

The getValue method takes a class instance parameter and returns the value of the corresponding introspected property for that instance:

   $testClass= new TestClass();   $property = new ReflectionProperty('TestClass', 'testProperty_1');   echo $property->getValue($testClass);

To set a value, use the setValue method and pass both a class instance and the new property value, for example:

   $testClass= new TestClass();   $property = new ReflectionProperty('TestClass', 'testProperty_1');   echo 'Before : '.$property->getValue($testClass).'
'; $property->setValue($testClass,"new_testProperty_1"); echo 'After : '.$property->getValue($testClass);

The ReflectionFunction—much like the ReflectionMethod and ReflectionProperty classes, lets you apply reflection to functions. To invoke a function, call the invoke method, passing parameters if required. The syntax is:

   public mixed invoke([mixed args [, ...]])

Here’s a simple example:

   $function = new ReflectionFunction('testFunction_1');   echo $function->invoke();

Finally, the ReflectionParameter class applies reflection to function or method parameters. To create a ReflectionParameter instance, pass the name of the function and the parameter position (as strings where arg1 is the first parameter, arg2 is the second, and so forth):

   $parameter = new ReflectionParameter('testFunction_2','arg1');   echo $parameter->getName();

To obtain the default value of a parameter, use the getDefaultValue method. You can also discover whether a particular function parameter is passed by reference or by value using the isPassedByReference method, which returns a Boolean true if the parameter is passed by reference.

See also  Custom Java Web Development - The Heartbeat of Modern Web Development

The Reflection API contains other classes not covered here, such as ReflectionException, ReflectionObject, ReflectionExtension, and ReflectionFunctionAbstract, which provide information about the types for which they’re named. For complete documentation and a tutorial see the official PHP5 manual.

Example 1: A Simple Reflection Application
The examples from this article were tested on the TestClass PHP class shown in Listing 1 and available in the downloadable code.

 
Figure 2. The CurrencyConverter Application: The sample application converts values between currencies.

Here’s an example that uses the Reflection API information from the previous section to develop a simple currency converter application. The starting point is an HTML page called index.htm that looks like the one you see in Figure 2. There’s nothing special about the page itself, but here’s the HTML:

          

Currency converter

Convert this amount:




From this currency:    To this currency

  

The interesting part begins after a user enters a value and selects the “from” and “to” currencies for the conversion. The dropdown lists each contain the abbreviations for three currency types: U.S. dollars (USD), Great Britain Pounds (GBP), and European Union Euros (EUR). When a user clicks the Exchange button, the form submits the data, and the server constructs a PHP class instance named CurrencyConverter, which contains six methods that accomplish all the possible conversions:

   

Because the conversion method depends on the currencies selected by the user, the application must determine the appropriate method to call at runtime. You could make that decision by using a set of conditional statements or by using the call_user_func method, but Reflection in PHP 5 provides a more elegant solution. Determining the appropriate method is simple. Notice how the CurrencyConverter methods are named: EUR_USD, USD_EUR, etc. When a user selects two currencies, the console submits the selected currency abbreviations. In the PHP code, you simply need to concatenate the submitted currency strings with an intervening underscore (_) character. For example, if the user elects to convert from euros (EUR) to pounds (GBP), the application calls the EUR_GBP method. The application actually makes the call using reflection. You can see the entire process in the code for the currencyconverter.php page:

   invoke($currencyConverter, $amount);      ?>

Example 2: Generating PHP Documentation with Reflection
One final example generates PHP class documentation using reflection—a task that requires deep class introspection, and thus uses many Reflection API methods.

First you need a simple HTML-based console that lets clients specify the name of the class to document. The console code could be as simple as this:

               Provide the class name to be documentated: 

The generatingDocumentation.php code in Listing 2 functions as the main component of the documentation application.

The page first retrieves the class name submitted by the user through the console, adds a file extension, includes the class, and then opens a file where it will write the output documentation:

      //get the class name to be documentated          $className=$_GET['class'];            //paste the name class with the extension .inc      $classNameExtension=$_GET['class'].".inc";      $b=$_GET['class'];            //include the $classNameExtension class       include($classNameExtension);            //get a ReflectionClass for the $className class      $reflection=new ReflectionClass($className);            //prepare the output      $hf=fopen("PTD.html","w");

Next it cycles through the various parts of the class, retrieving the interfaces the class supports, the name of its parent class (if any), constants, properties, and finally the methods, along with all their parameters. It writes all that information, including any description comments, into the documentation file. You can see the full code in Listing 2, but here’s the section that retrieves and documents a class’s methods and parameters:

   //get information about methods   $methods=$reflection->getMethods();            if($methods != null)         {        fwrite($hf,"	Methods:".        "".        "Name".        "".        "Modifiers".        "".        "Parameters".        "".        "Description".        "
");        foreach($methods as $in)         {         fwrite($hf,"	");         fwrite($hf,$in->getName());               if($in->isConstructor())                 { fwrite($hf," [c]"); }                    fwrite($hf,"");           if ($in->isPublic())                 { fwrite($hf,"[public]"); }          if ($in->isPrivate())                 { fwrite($hf,"[private]"); }         if ($in->isProtected())                 { fwrite($hf,"[protected]"); }          if ($in->isAbstract())                 { fwrite($hf,"[abstract]"); }          if ($in->isFinal())                 { fwrite($hf,"[final]"); }          if ($in->isStatic())                 { fwrite($hf,"[static]"); }          fwrite($hf,"");                              $parameters=$in->getParameters();         if($parameters != null)            {                              fwrite($hf,"");            $nr_parameters=count($parameters);            foreach($parameters as $out)          {
 
Figure 3. PHP Documentation Output: The PHP Documentation Tool application emits documentation showing the interfaces, superclass, constants, properties, and methods.
fwrite($hf,"$"); fwrite($hf,$out->getName()); if($out->isPassedByReference()) { fwrite($hf,"  [&]  "); } if($out->allowsNull()) { fwrite($hf,"  [+]  "); } } fwrite($hf,""); }else { fwrite($hf,""); } fwrite($hf,""); fwrite($hf,$in->getDocComment()); fwrite($hf," "); } }

For example, if you provide the test class in Listing 1 to the PHP Documentation Tool, it will output the information shown in Figure 3.

As you have seen, the new Reflection API provides a good implementation of reflection, and gives you the tools to create more complex applications, such as the PHP Documentation Tool. You’ll find reflection particularly useful when you don’t know which class or method you need to execute at design time.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist