cult3

What is Reflection in PHP?

Jul 02, 2014

Table of contents:

  1. What is Reflection and why is it useful?
  2. Common PHP Reflection functions
  3. PHP Reflection Classes
  4. How does Laravel’s Reflection work?
  5. Conclusion

Reflection in software development is something that is used quite often, but rarely seems to be a topic that is taught when learning how to write code. For me, Reflection was really just a concept that I stumbled upon along the way, I had no idea of why you would use it or what kind of opportunities it would present.

Reflection is where an object is able to introspectively examine itself to inform you of it’s methods and properties at runtime.

On the face of it this doesn’t seem like something that would be particularly useful. However, Reflection is actually a really interesting aspect of software development and it is something that you will probably touch upon often.

In this article I’m going to be looking at how we can use Reflection in PHP.

What is Reflection and why is it useful?

Reflection, as the name implies, is the ability for a computer programme to inspect itself and tell you about the properties, methods and types of objects you are working with.

This is useful in a number of different ways and scenarios.

One of the most common ways in which Reflection is useful is for debugging your code. You’ve probably used the get_class() and get_class_methods() functions when working with an ambiguously named object. The ability to get the type or methods of an object when you don’t know what type of object it is, is Reflection.

Another common use of Reflection is for creating documentation. It would be extremely labour intensive to write documentation about every method of every class of a large framework or application. Instead, Reflection can automatically generate the documentation for you. It does this by inspecting each method, constructor and class to determine what goes in and what comes out.

Laravel also makes really good use of Reflection to automatically inject the dependencies of your classes through the IoC container. When you write something like this in Laravel:

class UserController
{
    public function __construct(User $user)
    {
        $this->user = $user;
    }
}

Laravel knows it needs to inject an instance of User. Laravel is able to do that by using Reflection to inspect the type hinted method argument and resolve the dependency automatically for you.

Common PHP Reflection functions

As I mentioned above, the two PHP Reflection functions that I use most often are get_class() and get_class_methods() when I’m working with someone else’s code. It’s often quicker to just dump an object out, rather than pull the thread to see where the object originated from.

Using these functions is really easy:

// An unknown object appeared!
var_dump(get_class($pokemon)); // Pokemon\Electricity\Pikachu

var_dump(get_class_methods($pokemon));
// Tail Whip
// Thunder Bold
// Thunder

The get_class() function will return a string of the class name and the get_class_methods() function will return an array of the available methods on the object.

Another common function is the method_exists() function. You will often see this used inside an object’s __get() or __set() magic methods to see if a getter or setter method is available on the object:

class User {

    protected function getUsername() {}

    public function __get($param)
    {
        $method = 'get'.ucfirst($param);

        if (method_exists($this, $method))

        return $this->{$method}();
    }
}

This allows you use getter and setter methods whilst still maintaining the nicer $user->username API. In the example above, the method_exists accepts the current object ($this) and the name of the method you are looking for ($method).

PHP Reflection Classes

I’ve highlighted a couple of PHP Reflection functions, and there are plenty of other inbuilt functions that allow you to perform many other introspection tasks on the objects in your code.

However, PHP also offers us a much more powerful way of performing Reflection through its Reflection API.

If you have a look through the PHP documentation, there is actually an overwhelming amount of classes and methods available to perform introspection in your code.

To be quite honest, unless you are building something that would only really be possible with Reflection, you won’t need to use many of these classes or methods.

Instead of trying to memorise them all, instead we’ll look at just a few of the most common things you will likely need when working with Reflection in PHP.

The class we will be inspecting will be the following. Copy the code into an editor so you can follow along too:

<?php namespace Facebook\Entities;

class UUID
{
}
abstract class Entity
{
}
interface Friendable
{
}
interface Likeable
{
}
interface Postable
{
}

class User extends Entity implements Friendable, Likeable, Postable
{
    public function __construct($name, UUID $uuid)
    {
    }
    public function like(Likebable $entity)
    {
    }
    public function friend(User $user)
    {
    }
    public function post(Post $post)
    {
    }
}

$reflection = new \ReflectionClass(new User("Philip Brown", new UUID(1234)));

Get the class name

The first Reflection method we will look at allows us to get the fully qualified name of the object:

echo $reflection->getName();
// Facebook\Entities\User

You can also get just the name of the class:

echo $reflection->getShortName();
// User

As well as just the namespace name:

echo $reflection->getNamespaceName();
// Facebook\Entities

Get the parent class

Our User object has a parent abstract class. We can get an instance of that reflected class by calling the getParentClass() method. This will return a new ReflectionClass instance:

$parent = $reflection->getParentClass();
echo $parent->getName();
// Facebook\Entities\Entity

Get the interfaces

The User object implements a number of interfaces. We can reflect an array of the names of the interfaces by calling the getInterfaceNames() method:

$interfaces = $reflection->getInterfaceNames();

echo "<pre>";
var_dump($interfaces);
/*
array(3) {
[0]=>
string(28) "Facebook\Entities\Friendable"
[1]=>
string(26) "Facebook\Entities\Likeable"
[2]=>
string(26) "Facebook\Entities\Postable"
}
*/

You can also retrieve an array of interfaces as ReflectionClass instances by using the getInterfaces() method:

$interfaces = $reflection->getInterfaces();

echo "<pre>";
var_dump($interfaces);

/*
array(3) {
["Facebook\Entities\Friendable"]=>
&object(ReflectionClass)#3 (1) {
["name"]=>
string(28) "Facebook\Entities\Friendable"
}
["Facebook\Entities\Likeable"]=>
&object(ReflectionClass)#4 (1) {
["name"]=>
string(26) "Facebook\Entities\Likeable"
}
["Facebook\Entities\Postable"]=>
&object(ReflectionClass)#5 (1) {
["name"]=>
string(26) "Facebook\Entities\Postable"
}
}
*/

Get the class methods

A very common objective of using the ReflectionClass is the ability to determine what methods the object under inspection has:

$methods = $reflection->getMethods();
var_dump($methods);

echo "<pre>";
var_dump($methods);
/*
array(3) {
[0]=>
&object(ReflectionMethod)#2 (2) {
["name"]=>
string(4) "like"
["class"]=>
string(22) "Facebook\Entities\User"
}
[1]=>
&object(ReflectionMethod)#3 (2) {
["name"]=>
string(6) "friend"
["class"]=>
string(22) "Facebook\Entities\User"
}
[2]=>
&object(ReflectionMethod)#4 (2) {
["name"]=>
string(4) "post"
["class"]=>
string(22) "Facebook\Entities\User"
}
}
*/

This will return an array of ReflectionMethod objects. The ReflectionMethod object has a number of methods for further inspecting the characteristics of a class method. You can read more about this class here.

Get the Constructor

The final cool thing you can do with the ReflectionClass is get the constructor of the class:

$constructor = $reflection->getConstructor();

echo "<pre>";
var_dump($constructor);
/*
object(ReflectionMethod)#2 (2) {
["name"]=>
string(11) "__construct"
["class"]=>
string(22) "Facebook\Entities\User"
}
*/

The __construct() method is just a method so the ReflectionClass will return an instance of ReflectionMethod.

However, now that we’ve got an instance of ReflectionMethod, we can now get the dependencies of the class:

echo "<pre>";
var_dump($constructor->getParameters());
/*
array(2) {
[0]=>
&object(ReflectionParameter)#3 (1) {
["name"]=>
string(4) "name"
}
[1]=>
&object(ReflectionParameter)#4 (1) {
["name"]=>
string(4) "uuid"
}
}
*/

This will return an array of ReflectionParameter objects. We can then use Reflection to get instances of the dependency objects:

$parameters = $constructor->getParameters();

echo "<pre>";
var_dump($parameters[1]->getClass());
/*
object(ReflectionClass)#5 (1) {
["name"]=>
string(22) "Facebook\Entities\UUID"
}
*/

These are just some of the most common ReflectionClass methods you will likely encounter. However, a quick look at the documentation is all you need to know to understand that you can reflect and inspect just about every aspect of a PHP object. This is really powerful stuff!

How does Laravel’s Reflection work?

One of the most common questions I get here on Culttt is, “how does Laravel automatically inject the right dependencies into my class?”.

Laravel is able to automagically resolve your dependencies and inject them into your classes using PHP’s ReflectionClass. On the surface this seems like pure magic because using regular PHP would require you to do all of the work to inject dependencies manually.

However, under the surface, the method behind the magic is really just leveraging PHP’s Reflection abilities.

I’ve written previously about Laravel’s IoC Container, so I won’t cover old ground again.

Instead, in this article we’ll take a peek under the hood to see how Laravel’s IoC container is able to magically build objects using Reflection.

How does Laravel’s IoC container resolve dependencies?

Believe it or not, we’ve actually just covered exactly how the magic behind Laravel’s IoC container works already.

The Laravel IoC container class can be found here.

One of the most important methods of the IoC container is the build() method.

First the build() method creates a new ReflectionClass instance:

$reflector = new ReflectionClass($concrete);

Using the capabilities of the ReflectionClass, first it checks to see if the class is instantiable:

// If the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an Interface of Abstract Class and there is
// no binding registered for the abstractions so we need to bail out.
if (!$reflector->isInstantiable()) {
    $message = "Target [$concrete] is not instantiable.";

    throw new BindingResolutionException($message);
}

I find I get this exception when I haven’t added the Service Provider to app.php file under the config directory.

Next it gets the constructor just like we did above:

$constructor = $reflector->getConstructor();

If the class has no dependencies injected through the constructor there is no more Reflection that needs to be done. The IoC container can simply return a new instance of the object:

// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
if (is_null($constructor)) {
    return new $concrete();
}

If the class does have a constructor, the IoC container will then get the parameters that are being injected, and resolve instances of each using the ReflectionParameter object we used earlier:

$dependencies = $constructor->getParameters();

// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the Reflection instances to make a
// new instance of this class, injecting the created dependencies in.
$parameters = $this->keyParametersByArgument($dependencies, $parameters);

$instances = $this->getDependencies($dependencies, $parameters);

return $reflector->newInstanceArgs($instances);

So as you can see, the magic behind the Laravel curtain is really just plain old PHP using PHP Reflection capabilities.

The Reflection aspect of Laravel is really one of the nicest features of the framework. It solves the pain of having to instantiate and resolve dependencies for you, making your life easier, but also your code cleaner more testable.

However I think the best part about it is the fact that Laravel is using pure PHP instead of some hacky process to give the illusion of it working correctly.

Conclusion

So hopefully you will be able to see how powerful Reflection can be in PHP. Reflection allows you to inspect PHP objects at runtime. By being able to inspect the characteristics and capabilities of an object, you open up a whole new world of opportunity for using objects in an object oriented world.

However with that being said, Reflection is probably not going to be something that you use every day. The get_class() and get_class_methods() functions can be great for debugging or working through someone else code, but you probably won’t be flexing the capabilities of the ReflectionClass on a daily basis.

The Reflection is a very valuable aspect of the PHP programming language. Reflection allows us to do things that would be impossible without it. Whilst Reflection is not something that you will use everyday, it will certainly be a tool that you will call upon at some point in your career.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.