Want to get more articles like this one? Join my newsletter

PHP reflection API fundamentals

Do you ever take the time to read the code of your favourite PHP framework or library? If you have, there’s a good chance that you might have seen them use PHP’s reflection API. And, if you don’t read other people’s code, you should start doing it! (It’s a great learning tool.)

Now, let’s get back to the reflection API. This is an API that gets used quite a lot by framework and library developers. But the funny thing is that it’s almost never talked about when you’re looking at resources to learn PHP. (Or even advanced PHP resources for that matter.)

This is unfortunate. That’s because PHP’s reflection API serves a unique and important purpose. That’s why developers that build our frameworks and libraries use it so much.

What’s a reflection?

At this point, there’s a good chance that you’re telling yourself, “Well, of course, I don’t know PHP’s reflection API. I don’t even know what you mean by reflection!” That’s a reasonable reaction to have. (My bad!) It’s the one I had the first time I came across code that used reflections.

Let’s start by looking at the concept of reflection. The first thing that you should know is that the concept of reflection isn’t PHP specific. It’s a concept that comes from computer science.

Ok, that’s fine. But what is this mysterious concept of reflection? Well, it’s the idea that your code should be able to examine and modify itself while it’s running.

If that sounds trippy, that’s because it is! We often think of our code as something static. Once you save and execute it, there’s no way to make changes to it. But that’s not true. And reflections is the mechanism that you use to make changes to your code as it’s running.

While it might sound crazy today that you would want to edit your code as its running, that wasn’t always the case. Back when programmers used to program using an assembly language this was quite common. In fact, the examine your code and modify as it ran was an inherent property of an assembly language.

This property of assembly languages didn’t carry over when early compiled languages appeared. But it did eventually reappear through the concept of reflection. And now a lot of programming languages support it.

What do you use them for?

So that’s some of the history behind the concept of reflection. But this doesn’t really help you understand what you would use it for. Or even why it’s even useful. After all, you’ve been getting away with not using it for a while now.

The most common use for reflection is for testing. When you’re testing your code, you often need to examine and modify it as it’s running. It’s also how unit testing frameworks tend to create mocks of your classes and functions.

It’s also great for situations where you want to analyze code and automate some task around it. For example, documentation generation libraries can use reflections to generate documentation for your code. It’s also how a lot of dependency injection containers inject dependencies into the objects they create.

That said, as we’ll see throughout the article, there are a lot of uniques uses for reflections. They don’t always fit into neat categories like those we just mentioned. But what they all have in common is that they use reflections to inspect and modify code as it’s running.

Overview of the PHP reflection API

Let’s move on to the reflection API. If you went to check the PHP documentation earlier (here‘s the link again), you might have noticed that it’s massive. There are over a dozen classes, and some of them have dozens of methods.

It’s not realistic (or even useful for us) to go over all of them. What we’ll do instead is look at the reflection API from a high level. And, from there, we’ll look the reflection classes that you’re the most likely to use.

How are reflection classes structured?

While there are a lot of reflection classes, how they related to one another is pretty easy to understand. That’s because, in general, every PHP construct has a corresponding reflection class. What do we mean by that?

Well, let’s say that you have a class that you’d like to examine. The reflection class that you’d use to do that is the ReflectionClass class. (Quite the obvious class name!) But if you had an object that you wanted to inspect, you’d use the ReflectionObject class instead. (You must be getting the idea!)

$classReflection = new ReflectionClass('SomeClass');

$object = new SomeClass();
$objectReflection = new ReflectionObject($object);

Above is how you’d create a reflection of the SomeClass class and a reflection of the SomeClass object. It’s worth noting that, while we use two different classes to generate our reflections, both reflections are almost identical. In fact, the ReflectionObject class extends the ReflectionClass class.

In practice, there’s no reason to use one reflection class over the other. You should just use the one that fits the information you have at the time. If you just have the class name, use the ReflectionClass class. If you have an object, use the ReflectionObject class instead.

Let’s get back to our reflection objects. Once we’ve instantiated one of them, we can then use its class methods to examine the SomeClass class. This allows us to get answers to specific questions like:

Diving further into reflections

But you can dig even deeper and fetch a specific constant, method or property from a class. Or you can get them all. Let’s look at a small example of this in action.

$object = new SomeClass();
$objectReflection = new ReflectionObject($object);

$someProperty = $objectReflection->getProperty('someProperty');

Now, the question with this example is what did we store in the someProperty variable? Well, it happens that what we got from the getProperty method is another reflection. This reflection isn’t an instance of ReflectionClass either. It’s an instance of the ReflectionProperty class.

This brings us to an important fact about examining code with reflections. It’s that, with reflections, you’re often just dealing with other reflection classes. It’s a bit like going down a rabbit hole!

That said, it’s is also a useful way to view the structure of these reflection classes. Let’s imagine that you create a reflection using ReflectionClass or ReflectionObject. What you’ll get is an instance of that class where:

Getting information from reflections

Let’s say that you’ve drilled down to the reflection object that you need. How do you get concrete information out of it? For example, how would you get the value stored in the property of an object?

Well, first, you have to think about what information you want to get. In this case, we want to get the value of a property of an object. And then you have to ask yourself what is the most specific reflection that would contain this information.

$object = new SomeClass();
$objectReflection = new ReflectionObject($object);

$somePropertyReflection = $objectReflection->getProperty('someProperty');

$somePropertyValue = $somePropertyReflection->getValue($object);

The code above builds on our earlier example. We initialized a SomeClass object. We then created a reflection of it using the ReflectionObject class.

Next, we want to access the someProperty property from our SomeClass object. We do that by fetching its reflection from our ReflectionObject object. We do that using the getProperty method which returns a ReflectionProperty object.

We also stored that ReflectionProperty object in the somePropertyReflection variable. We can then use it to get the value stored in the someProperty property. We do that using the getValue method. We then stored that value in the somePropertyValue variable.

Reflections are never reflections of a specific object

Now, you might have also noticed odd about our call to the getValue method. It’s that we passed it our object as an argument. Why did we do that? After all, didn’t we instantiate our ReflectionObject object using our SomeClass object?

It’s true that we did instantiate our ReflectionObject object using our SomeClass object. But the fact is that it doesn’t matter that we did that. Our ReflectionObject object doesn’t contain any information about our SomeClass object.

This is one of the more confusing parts of using reflections. Considering how we instantiate it, you’d think that our ReflectionObject object would be smarter. That it’d contain information about the object that we reflected.

But that’s not the case. That’s because, when you create a ReflectionObject object, you’re not creating a reflection of that object. Instead, what’s happening is that the ReflectionObject class creates a reflection of the class of the object that you gave it. (That’s also why the ReflectionObject class extends the ReflectionClass class.)

So, if we go back to our example, the objectReflection isn’t a reflection of object. It’s a reflection of the SomeClass class. It’s unintuitive at first, but you get the hang of it eventually.

The same goes for all the other types of reflections

What happens then when we make a call to the getProperty method of our ReflectionObject object? Well, in that case too, you’re not getting a reflection of the property of an object. You’re getting the reflection of a property of a class.

This means that, in our example, someProperty isn’t the reflection of the someProperty property of object. It’s the reflection of the someProperty property of the SomeClass class. And that’s why we have to pass object to the getValue method.

Again, this isn’t very intuitive when you start using reflections. That said, there are benefits to things working the way they do. For example, it means that we don’t need to create multiple reflections of the someProperty property. If we have to examine two SomeClass objects, we can do this instead:

$object1 = new SomeClass();
$object2 = new SomeClass();

$objectReflection = new ReflectionObject($object1);

$somePropertyReflection = $objectReflection->getProperty('someProperty');

$somePropertyValue1 = $somePropertyReflection->getValue($object1);
$somePropertyValue2 = $somePropertyReflection->getValue($object2);

In the example above, we managed to extract two someProperty values using the same ReflectionProperty object. First, we started by creating a reflection of the someClass class. We created it by using the ReflectionObject class and passing it object1. (We could have also used object2.)

Using our objectReflection, we get a reflection of the someProperty property. We then use it to extract the value of the someProperty property from both our objects. We then store those values in the somePropertyValue1 and somePropertyValue2 variables.

Reflections in practice

While we haven’t seen everything that reflections can do, it’s a good starting point. What we’re going to do next is look at how to use reflections in a more practical context. This will allow us to go over other aspects of reflections that we haven’t covered so far.

A class to reflect

But first, we need a class that we can reflect! We don’t need to make this class too complicated. It just needs methods and properties that aren’t public. (You don’t need for reflections to inspect public methods or properties!)

class User
{
    /**
     * The user ID.
     *
     * @var int
     */
    private $id;

    /**
     * The user's login.
     *
     * @var string
     */
    private $login;

    /**
     * The user's password.
     *
     * @var string
     */
    private $password;

    /**
     * Constructor.
     *
     * @param string $login
     * @param string $password
     */
    public function __construct($login, $password)
    {
        $this->login = $login;
        $this->password = $password;
    }
}

So above is a small class called User that we’ll use for more practical examples. It has three internal private properties: id, login and password. For now, it doesn’t have any other methods besides the constructor.

The constructor itself has two parameters: login and password. Those are two of the three internal properties that our User class has. All that the constructor does is assigns the login and password arguments passed to it to the login and password internal variables.

Now, you might wonder why we didn’t put id as a parameter of our constructor. It’s because you don’t always have or need the id of a user when you’re creating a User object. For example, a new user might not have its ID assigned to it right away.

Assigning a value to a private or protected property

But what happens if you want to assign a value to the id of a user? Well, you could create a setter method. But this would mean that anyone can set a new ID to a user at any time.

This isn’t an ideal solution because the ID of a user shouldn’t change if there’s one. That said, this could also be part of the logic of the setter method. If a user already has an ID, don’t assign it a new one like this:

class User
{
    // ...

    /**
     * Set the ID of a user.
     *
     * @param int $id
     */
    public function setId($id)
    {
        if (!empty($this->id)) {
            return;
        }

        $this->id = $id;
    }
}

Using a reflection instead of a method

However, even if the setId method prevents someone from overwriting the id property, it doesn’t mean that the method should exist. Instead of creating the setId method, you could use reflections to add the id to a User object whenever you need it. Let’s look at how we can do that.

class UserRepository
{
    /**
     * The user's login.
     *
     * @var mysqli
     */
    private $mysql;

    // ...

    public function persist(User $user) 
    {
        $result = $this->mysql->query('INSERT INTO ...');

        if (!$result) {
            throw new \Exception($this->mysql->error);
        }

        $userReflection = new ReflectionObject($user);
        $idPropertyReflection = $userReflection->getProperty('id');

        $idPropertyReflection->setAccessible(true);
        $idPropertyReflection->setValue($user, $this->mysql->insert_id);
        $idPropertyReflection->setAccessible(false);

        return $user;
    }
}

Above we have part of the UserRepository class. If you’re not familiar with the concept of repository, it’s class that acts as a collection of objects. If you need a persistence layer, it can also handle persisting objects inside a database. (If that’s what you use for persistence.)

This is what the persist method does. It takes a User object as an argument and persists it in the MySQL database. Only once we’ve persisted our User object do we assign it an id.

So instead of using a setId method to assign the id, we’re using reflections. But first, we need to save our User object inside the database. To do that, our UserRepository class uses the mysqli class. This is a PHP class used to represent a connection with a MySQL database.

Our UserRepository already has an instantiated mysqli object stored in the mysql property. So we can assume that our connection to the MySQL database works already. All that we have to do then is create a query to insert our new user into the database.

We do that using the query method to run an INSERT query. We’re not showing the query because it’s not relevant here. That said, never forget to sanitize your database inputs if you run queries like this!

We store the result of the query in the result variable. We then check to see if it’s false. If it is, we throw an exception with the error message stored in the error property of the mysqli object.

Once we’re passed this guard clause, we can start using our reflections. First, we create a reflection of the User object using the ReflectionObject class. Then we create a reflection of the id property using the getProperty method of our User reflection.

Changing the accessibility of a property

This shouldn’t feel too new to you as it’s what we saw earlier about diving into reflections. What’s new is the last half of this section. It’s where we change the value of an internal variable of an object.

By default, reflections don’t override the scope of a variable. This means that, while we have a reflection of the id property, we can’t do much with it. It’s still a private property.

To change that, we need to use the setAccessible method. This changes the scope of a property to public. Once we’ve done that, the ReflectionProperty object will let us modify the value of the id property.

At that point, all that we have to do is call the setValue method. We pass it our User object and the ID of the user we inserted in the database. The mysqli object always stores that ID in the insert_id property.

Once we’ve set the value of the id property, we need to revert the accessibility change that we did at first. Otherwise, the id property will stay accessible as long as the object exists. (And we don’t want that!) That’s why we make a call to the setAccessible method once more after the call to the setValue method.

Calling a private or protected method

We can also do what we just did for private or protected properties with object methods. We can take a private or protected method and make it public so that we can use it. This is also something that can be useful in certain scenarios.

class User
{
    // ...

    /**
     * Constructor.
     *
     * @param string $login
     * @param string $password
     */
    public function __construct($login, $password)
    {
        $this->login = $login;
        $this->password = $this->maybeEncode($password);
    }

    /**
     * Encodes the password using the BCRYPT algorithm if it's not already
     * encoded.
     *
     * @param string $password
     *
     * @return string
     */
    private function maybeEncode($password)
    {
        if (!password_needs_rehash($password, PASSWORD_BCRYPT)) {
            return $password;
        }

        return password_hash($password, PASSWORD_BCRYPT);
    }
}

Above is an updated version of our User class. We added a new private method called maybeEncode. The purpose of this method is to encode our password if it wasn’t encoded already. We do that by using two built-in PHP functions: password_needs_rehash and password_hash.

The maybeEncode method starts with a guard clause. We use the password_needs_rehash function to check if we need to encode the given password. If we don’t need to, we return it. Otherwise, we password_hash function to encode the given password.

It’s also worth noting that both functions have a second argument where we pass the PASSWORD_BCRYPT constant. This is the password algorithm constant that we’ll use to encode the given password. You can also use the PASSWORD_DEFAULT constant if you prefer to not specify an algorithm. That said, PASSWORD_BCRYPT is the current PASSWORD_DEFAULT value.

Using a method reflection

Now that we have a private method in our User class, we can look at how to create a reflection for it. This is pretty straightforward and follows the similar pattern that we’ve seen so far. You can view the code below:

$userReflection = new ReflectionObject($user);

$maybeEncodeReflection = $userReflection->getMethod('maybeEncode');

$maybeEncodeReflection->setAccessible(true);
$maybeEncodeReflection->invoke($user, $password);
$maybeEncodeReflection->setAccessible(false);

Unlike our previous example with the UserRepository class, this is just a code sample. That said, you’ll notice that we once again start by reflecting our User object using the ReflectionObject class. You could have used the ReflectionClass class instead if you wanted as well.

After that is where things diverge a bit. First, we do a call to the getMethod method. We use it to ask for a reflection of the maybeEncode method.

Next, we want to make the method accessible. We use the setAccessible method like we did with our private property. This will allow us to use our maybeEncode method.

To make a call to a method reflection, you have to use the invoke method. The invoke works the same way as the other reflection methods that we’ve seen so far. You have to first pass it the object that you want the reflection to interact with.

Generating a closure

There’s also another way to access a private method using reflections. It’s by generating a closure for the method that we want to reflect. Here’s an example to show you how to do it:

$userReflection = new ReflectionObject($user);

$maybeEncodeReflection = $userReflection->getMethod('maybeEncode');

$maybeEncodeClosure = $maybeEncodeReflection->getClosure($user);

$maybeEncodeClosure($password);

As you might have noticed, this is a modified version of our previous example. The first part of the example is the same. We created a reflection of our User object. We then used that reflection to create a reflection of the maybeEncode method.

The last section of the example is where things changed. First, we don’t use setAccessible method. We don’t need to change the accessibility of the maybeEncode method to use it in this scenario.

Instead, we only need to call the getClosure method. This generates a Closure object. This object calls the maybeEncode method in the User object that we passed it.

We do that on the last line. We use the maybeEncodeClosure variable as a function. We pass it our password as an argument.

A good foundation

This is only a fraction of all that you can do using reflections. As we said at the beginning, this covers the most common uses of reflections. There are a lot more classes and methods, but their use is a lot more situational.

With what you’ve seen here, you’re in good shape to use reflections to solve interesting problems. That said, most of its use will be around testing. Reflections and testing often go hand in hand.

So, if you’re interested in testing, this is all good knowledge to have! But regardless that you do testing or not (you should though!), reflections are important computer science concept. You might encounter them in another programming language later in your career.

Photo Credit: Erik Eastman

Creative Commons License