Chris Tankersley

  • Home
  • About
  • Portfolio
  • Projects
Twitter RSS

Getting Started with Reflection

Posted on September 3, 2010 by Chris
2 commentsLeave a comment

Reflection is a metaprogramming construct that allows a program to look into itself and do a multitude of different things – gain meaning, watch execution, call code, or even provide feedback. In PHP this sort of thing is more oriented to frameworks, but the power of reflection can be harnessed to do a lot of different things.

With PHP 5, PHP gained a robust reflection class that allows a developer to gain access to just about every aspect of an object and interact with it. The key is figuring out what is available, and then exploiting it to gain additional benefits.

Part of PhpORM, an object-relational-mapper project that I’ve been working on, that I’ve wanted to do is make it easy to create databases based on PHP objects without a lot of overhead. Doctrine does this well in 1.2 (which is really the only version I’ve used) by allowing a developer to generate schemas from yaml files and compile them into PHP objects. One thing I don’t like about Doctrine is that it gets kind of confusing pretty quickly and was a major turn off for me the first few times I tried to use it. I also like to keep as much in my PHP code as I can.

One feature of PhpORM is the SQL generation comments (which is somewhat of a misnomer – they are used right now for SQL generation, but will be expanded into more). Let’s set up a basic entity so that we have something to work with:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
    /**
     * For the sake of demonstration, we're setting this private
     */
    private $_allowDynamicAttributes = false;
 
    /** type=primary_autoincrement */
    protected $id = 0;
    /** type=varchar length=255 null */
    protected $name;
    /** type=text null */
    protected $biography;
}

The ReflectionClass

One of the main components in reflection programming in PHP is the ReflectionClass. This core class allows a developer to starting digging through an object and pulling out information. What kind of information? Here’s a small taste:

  • Constants
  • Property Names
  • Method Names
  • Static properties
  • Namespace
  • If the Class is abstract or final

That’s just a small sampling.

Getting Started

So how do we start reflecting on a class to get this information? Just pass it the name of a class:

1
$class = new ReflectionClass('Person');

Really, that’s all there is too it. The $class object has now associated itself with a specific class (in this case our Person class) and we can start inquiring on it.

Getting Properties

Let’s find out what properties are in our class and print them out. To do this, we just call getProperties(), which returns an array of ReflectionProperty objects:

1
2
3
4
5
6
7
8
9
$properties = $class->getProperties();
foreach($properties as $property) {
    echo $property->getName()."\n";
}
// Output:
// _allowDynamicAttributes
// id
// name
// biography

By default the ReflectionClass will return all of the members of a class, not just public ones. You can alter this by passing a parameter to getProperties(). Valid parameter values are ReflectionProperty::IS_STATIC, ReflectionProperty::IS_PUBLIC, ReflectionProperty::IS_PROTECTED, and ReflectionProperty::IS_PRIVATE.

1
$private_properties = $class->getProperties(ReflectionProperty::IS_PRIVATE);

Working with Properties

Now that we have a list of properties, we can start to get more information about them instead of the class as a whole. As we can see above, we can get the name of a property via getName(). We can also get the DocBlock comments, the status of a property, and get or set values on objects. Since we’re looking to get information about the properties in Person, and that metadata is stored in the DocBlock, let’s extract that information.

1
2
3
4
5
6
7
8
9
10
11
foreach($properties as $property) {
    if($property->isProtected()) {
        $docblock = $property->getDocComment();
        preg_match('/ type\=([a-z_]*) /', $property->getDocComment(), $matches);
        echo $matches[1]."\n";
    }
}
// Output:
// primary_autoincrement
// varchar
// text

Since the _allowDynamicAttributes is private, it was skipped (not that it would have matched the regex anyway).

Getting Methods

Getting Methods and working with them is just like with Properties. You can use getMethods() to get an array of ReflectionMethod objects, and from those get their names, comments, prototypes, statuses, etc.

Let’s say that we had put getters (getId(), getName(), getBio()) and setters (setId(), setName(), setBio()) on our entity class. We want to set each property and retrieve it. If the setter or getter doesn’t exist, throw an exception.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$data = array('id' => 1, 'name' => 'Chris', 'bio' => 'I am am a PHP developer');
foreach($data as $key => $value) {
    if(!$class->hasProperty($key)) {
        throw new Exception($key.' is not a valid property');
    }
 
    if(!$class->hasMethod('get'.ucfirst($key))) {
        throw new Exception($key.' is missing a getter');
    }
 
    if(!$class->hasMethod('set'.ucfirst($key))) {
        throw new Exception($key.' is missing a setter');
    }
 
    // Make a new object to interact with
    $object = new Person();
 
    // Get the getter method and invoke it with the value in our data array
    $setter = $class->getMethod('set'.ucfirst($key));
    $setter->invoke($object, $value);
 
    // Get the setter method and invoke it
    $setter = $class->getMethod('get'.ucfirst($key));
    $objValue = $setter->invoke($object);
 
    // Now compare
    if($value != $objValue) {
        echo 'Getter or Setter has modified the data.';
    } else {
        echo 'Getter and Setter does not modify the data.';
}

Depending on what exactly happens with the getter and setter methods will determine the comparison result. If we’re missing any getters and setters, this test will alert us and we can fix it.

Start Reflecting On Your Code

See what I did there? Yeah, I’m sorry too. Anyway, hopefully this sheds a bit of light on the Reflection powers that are inherent in PHP. You can reflect on more than just Classes. There are reflection bits for functions, extensions, objects, even parameters. Once you get a grasp on reflection and what it can do, you gain just that extra bit of power of your code.

If you want to see reflection in action, take a look at PhpORM_Cli_GenerateSql. It uses reflection to build a CREATE TABLE statement based upon an entity, all using reflection.

Categories: Uncategorized

About Chris

View all posts by Chris→
Notice: This work is licensed under a BY-NC-SA. Permalink: Getting Started with Reflection
ZendCon 2010 – Day 1
Running PHPUnit With the IBM i

2 Responses to “Getting Started with Reflection”

  1. xrado says:
    September 4, 2010 at 3:32 am

    well explained!

  2. boombick says:
    September 18, 2010 at 9:13 am

    Thanks a lot

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

*

*


question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

  • Search

  • Archives

    • January 2012
    • September 2011
    • August 2011
    • April 2011
    • December 2010
    • November 2010
    • September 2010
    • August 2010
    • May 2010
    • April 2010
    • February 2010
    • January 2010
    • November 2009
    • October 2009
    • September 2009
    • June 2009
    • May 2009
    • February 2009
    • January 2009
    • November 2008
    • October 2008
    • July 2008
    • May 2008
    • February 2008
    • December 2007
    • October 2007
    • August 2007
    • July 2007
    • June 2007
    • May 2007
  • Categories

    • Code Releases
    • Doing Development
    • Hardware
    • IBM i
    • JavaScript
    • MySQL
    • Non-Programming
    • Operating Systems
    • Personal
    • PHP
    • Programming
    • Project Management
    • Reviews
    • Servers
    • Software
    • This Site
    • Tutorials
    • TWS Software
    • Uncategorized
    • ZendCon 2010
© Chris Tankersley. Proudly Powered by WordPress | Nest Theme by YChong