Working with Reflected Properties with the Reflection API

In this fourth part of a seven-part series, I demonstrate how to use the PHP reflection API to retrieve useful information about the properties declared by a specific class. Reflection allows you to do more with properties of a class than determine their visibility or learn the values assigned to them, but that’s what we’ll be covering here.

In case you’re not aware of it, among the many enhancements and helpful features that were added to PHP 5, there’s one that has been unfairly overlooked by many developers. This might be because at first glance it doesn’t seem to be as useful as the others. Yes, as this article’s title suggests, I’m talking about the reflection API, a powerful set of methods that permits you to perform an in-depth reverse engineering process on both classes and interfaces, in this way expanding the language’s introspective capabilities.

Fortunately, the API has progressively come out of the shadows of indifference, and nowadays its popularity has grown considerably. It’s being used in a huge variety of scenarios and situations, ranging from creating low-level dispatcher classes in MVC-based frameworks, to building dependency injection containers.

Of course, it’s possible that you still haven’t had the chance to explore this API in depth and discover what it can do for you. If that’s the case, in the course of this article series, I’m going to show you how to work with its most relevant methods, so you can start taking advantage of reflection within your own web applications.

I left off the previous tutorial explaining how to use the reflection API to get relevant information about the methods defined by a sample class, including the ability to learn if the methods in question were declared public, protected or private. However, the power of reflection doesn’t stop here; it allows you to analyze class properties with a similar level of introspection.

If this topic has caught your attention, in the following lines I’m going to code some friendly examples to demonstrate the functionality of the PHP reflection API when it comes to inspecting properties of a class.

Now, let’s get rid of the dull theory and learn more about using reflection in PHP 5. Let’s get going!

{mospagebreak title=Review: working with reflected methods}

In case you haven’t yet read the previous part of the series, where I discussed how to use the power of reflection to get relevant information about the methods defined by a sample class, below I reintroduced the definition of this class and the interfaces that it implements.

Take a close look at these sample structures:

interface Identifier

{

    public function setId($id);

   

    public function getId();

    

}

 

 

 

/**

* A sample user class

*

* @param  id fname lname email

*/

class User implements Identifier

{

    private $id = NULL;

      private $fname = ‘Alejandro';

    private $lname = ‘Gervasio';

    private $email = ‘alejandro@domain.com';

    const HEADING = ‘Using the Reflection API in PHP 5′;

   

    // constructor (not implemented)

    public function __construct(){}

   

    //setter for id property

    public function setId($id)

    {

        if (!is_numeric($id))

        {

            throw new Exception(‘ID must be a numeric value’);

        }

        $this->id = $id;

    }

   

    // getter for id property

    public function getId()

    {

        return $this->id;

    }

       

    // setter for fname property

    public function setFirstName($fname)

    {

        if (empty($fname) OR !is_string($fname))

        {

            throw new Exception(‘First name must be a non-empty string.’);

        }

        $this->fname = $fname;

    }

   

    // getter for fname property

    public function getFirstName()

    {

        return $this->fname;

    }

   

    // setter for lname property

    public function setLastName($lname)

    {

        if (empty($fname) OR !is_string($fname))

        {

            throw new Exception(‘Last name must be a non-empty string.’);

        }

        $this->lname = $lname; 

    }

   

    // getter for lname property

    public function getLastName()

    {

        return $this->lname;

    }

   

    // setter for email property

    public function setEmail($email)

    {

        if (empty($email) OR !is_string($email) OR strpos($email, ‘@’) === FALSE)

        {

            throw new Exception(‘Email must be a well-formatted email address.’);

        }

        $this->email = $email; 

    }

   

    // getter for email property

    public function getEmail()

    {

        return $this->email;

    }         

}

 

Obviously, in this case the “Identifier” interface and its implementing class have been coded only for demonstration purposes, since they do nothing particularly useful. Things become more interesting, though, when the methods of this sample class are inspected through reflection. That’s exactly what the following script does, so pay attention to it, please: 

// create instance of ‘User’ class

$user = new User();

 

 

 

// create instance of Reflection class and pass in ‘User’ class as argument

$reflector = new ReflectionClass(‘User’);

 

 

 

// get a ReflectionMethod object

$method = $reflector->getMethod(‘getFirstName’);

 

 

 

// check to see if the reflected method is public, protected or private

if ($method->isPublic())

{

    echo ‘The method is public'; // displays ‘The method is public’

   // invoke the reflected method

   echo $method->invoke($user); // displays ‘Alejandro’   

}

elseif ($method->isProtected())

{

    echo ‘The method is protected';

}

elseif ($method->isPrivate())

{

    echo ‘The method is private';

}

elseif ($method->isStatic())

{

    echo ‘The method is static';

}

 

 

 

// get all public methods of reflected class

print_r($reflector->getMethods(ReflectionMethod::IS_PUBLIC)); // displays Array ( [0] => ReflectionMethod Object ( [name] => __construct [class] => User ) [1] => ReflectionMethod Object ( [name] => setId [class] => User ) [2] => ReflectionMethod Object ( [name] => getId [class] => User ) [3] => ReflectionMethod Object ( [name] => setFirstName [class] => User ) [4] => ReflectionMethod Object ( [name] => getFirstName [class] => User ) [5] => ReflectionMethod Object ( [name] => setLastName [class] => User ) [6] => ReflectionMethod Object ( [name] => getLastName [class] => User ) [7] => ReflectionMethod Object ( [name] => setEmail [class] => User ) [8] => ReflectionMethod Object ( [name] => getEmail [class] => User ) )

 

As you can see above, determining the level of visibility assigned to one or more methods of the pertinent “User” class, or directly invoking them from client code, is only a matter of calling the proper methods provided by the reflection API and nothing else. In addition, the last line of the previous script also shows how to get all of the public methods defined by “User,” which is accomplished by passing the “IS_PUBLIC” constant defined by the built-in ReflectionMethod class to the “getMethods()” method.

So far, so good. Now that you’ve learned how to easily manipulate methods of a class via reflection, it’s time to explore other methods of the API. Thus, in keeping with the concepts just deployed in the introduction, in the segment to come I’m going to discuss how to take advantage of reflection for retrieving useful information about the properties declared by the previous “User” class.

To learn more about this brand new process, click on the link below and read the following section.

{mospagebreak title=Manipulating properties of a reflected class}

Frankly speaking, the process of getting and manipulating properties of a reflected class is very similar to the one used for working with reflected methods. To illustrate this concept, below I coded a simple example that shows how to retrieve all of the properties declared by the previous “User” class and determine their level of visibility. The example is as follows:  

// create instance of ‘User’ class

$user = new User();

 

 

 

// create instance of Reflection class and pass in ‘User’ class as argument

 

$reflector = new ReflectionClass(‘User’);

 

 

 

// check the visibility of retrieved properties

foreach ($reflector->getProperties() as $property)

{

    if ($property->isPublic())

    {

        echo ‘Property : ‘ . $property->getName() . ‘ is public<br />';

    }

    elseif ($property->isProtected())

    {

        echo ‘Property : ‘ . $property->getName() . ‘ is protected<br />';

    }

    elseif ($property->isPrivate())

    {

        echo ‘Property : ‘ . $property->getName() . ‘ is private<br />';

    }

    /*displays the following

    Property : fname is private

    Property : lname is private

    Property : email is private

    */

}

 

See how easy it is to obtain relevant information about the properties of a class via reflection? I bet you do! In the above example, the visibility assigned to the properties of the “User” class is determined by first creating a new ReflectionProperty object, and then by using its “isPublic(),” “isProtected()” and “isPrivate()” methods. Naturally, the reflection API makes it easier to manipulate class properties in all sorts of clever ways, but for the sake of brevity I’ll keep the examples shown in this and other tutorials rather simple, so you can more quickly grasp its underlying logic.

Having demonstrated how to use reflection to learn the level of visibility assigned to each property of the “User” class, in the last section of this article I’m going to show you how to get all of the properties of that sample class in one single step.

To learn the full details of this process, click on the link below and read the next few lines.

{mospagebreak title=Getting all the properties of the User class}

As I said in the preceding segment, getting all of the properties defined by the previous “User” class is really a breeze. The “User” class that you saw before defines only three private properties, but anyway it’s worthwhile to code an example, so you can see how easy is to accomplish this task.

Having said that, here’s a script that retrieves in one go all of the properties declared by “User”:

// create instance of ‘User’ class

$user = new User();

 

 

 

// create instance of Reflection class and pass in ‘User’ class as argument

 

 

 

$reflector = new ReflectionClass(‘User’);

 

 

 

// get properties of reflected class

print_r($reflector->getProperties()); // displays Array ( [0] => ReflectionProperty Object ( [name] => id [class] => User ) [1] => ReflectionProperty Object ( [name] => fname [class] => User ) [2] => ReflectionProperty Object ( [name] => lname [class] => User ) [3] => ReflectionProperty Object ( [name] => email [class] => User ) )

 

There you have it. Once a reflector object has been created, fetching all of the properties declared by the “User” class is reduced to calling the “getProperties()”reflection method and nothing else. What else can you ask for?

Again, I’d like to clarify that the reflection API permits you to handle class properties in many other helpful and creative ways. However, in this series I only intended to introduce you to using the API’s most relevant methods in a few concrete cases. Learning the remaining ones will be left completely up to you.  

Final thoughts

In this fourth part of the series, I demonstrated with a few basic examples how to use the PHP reflection API to retrieve useful information about the properties declared by a specific class. It’s fair to mention, though, that reflection allows you to do much more with properties of a class, aside from determining their visibility or knowing the values assigned to them. At the risk of being repetitive, the best place to get a full reference of reflection methods is the official PHP web site, so go ahead and take a look at it. It’s really worthwhile, trust me.

Moving forward, in the upcoming tutorial I’m going to explore other useful reflection methods, which will allow you to get more detailed information about the properties of a class, such as if they’re static or even whether or not a specified property exists.

Here’s my recommendation: don’t miss the next part!

[gp-comments width="770" linklove="off" ]

chat