Advertisement

Reflection in PHP

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

Reflection is generally defined as a program's ability to inspect itself and modify its logic at execution time. In less technical terms, reflection is asking an object to tell you about its properties and methods, and altering those members (even private ones). In this lesson, we'll dig into how this is accomplished, and when it might prove useful.


A Little History

At the dawn of the age of programming, there was the assembly language. A program written in assembly resides on physical registers inside the computer. Its composition, methods and values could be inspected at any time by reading the registers. Even more, you could alter the program while it was running by simply modifying those registers. It required some intimate knowledge about the running program, but it was inherently reflective.

As with any cool toy, use reflection, but don't abuse it.

As higher-level programming languages (like C) came along, this reflectivity faded and disappeared. It was later re-introduced with object-oriented programming.

Today, most programming languages can use reflection. Statically typed languages, such as Java, have little to no problems with reflection. What I find interesting, however, is that any dynamically-typed language (like PHP or Ruby) is heavily based on reflection. Without the concept of reflection, duck-typing would most likely be impossible to implement. When you send one object to another (a parameter, for example), the receiving object has no way of knowing the structure and type of that object. All it can do is use reflection to identify the methods that can and cannot be called on the received object.


A Simple Example

Reflection is prevalent in PHP. In fact, there are several situations when you may use it without even knowing it. For example:

// Nettuts.php

require_once 'Editor.php';

class Nettuts {

	function publishNextArticle() {
		$editor = new Editor('John Doe');
		$editor->setNextArticle('135523');
		$editor->publish();
	}

}

And:

// Editor.php

class Editor {

	private $name;
	public $articleId;

	function __construct($name) {
		$this->name = $name;
	}

	public function setNextArticle($articleId) {
		$this->articleId = $articleId;
	}

	public function publish() {
		// publish logic goes here
		return true;
	}

}

In this code, we have a direct call to a locally initialized variable with a known type. Creating the editor in publishNextArticle() makes it obvious that the $editor variable is of type Editor. No reflection is needed here, but let's introduce a new class, called Manager:

// Manager.php

require_once './Editor.php';
require_once './Nettuts.php';

class Manager {

	function doJobFor(DateTime $date) {
		if ((new DateTime())->getTimestamp() > $date->getTimestamp()) {
			$editor = new Editor('John Doe');
			$nettuts = new Nettuts();
			$nettuts->publishNextArticle($editor);
		}
	}

}

Next, modify Nettuts, like so:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		$editor->setNextArticle('135523');
		$editor->publish();
	}

}

Now, Nettuts has absolutely no relation to the Editor class. It does not include its file, it does not initialize its class and it does not even know it exists. I could pass an object of any type into the publishNextArticle() method and the code would work.

Class Diagram

As you can see from this class diagram, Nettuts only has a direct relationship to Manager. Manager creates it, and therefore, Manager depends on Nettuts. But Nettuts no longer has any relation to the Editor class, and Editor is only related to Manager.

At runtime, Nettuts uses an Editor object, thus the <<uses>> and the question mark. At runtime, PHP inspects the received object and verifies that it implements the setNextArticle() and publish() methods.

Object Member Information

We can make PHP display the details of an object. Let's create a PHPUnit test to help us easily exercise our code:

// ReflectionTest.php

require_once '../Editor.php';
require_once '../Nettuts.php';

class ReflectionTest extends PHPUnit_Framework_TestCase {

	function testItCanReflect() {
		$editor = new Editor('John Doe');
		$tuts = new Nettuts();
		$tuts->publishNextArticle($editor);
	}

}

Now, add a var_dump() to Nettuts:

// Nettuts.php

class NetTuts {

	function publishNextArticle($editor) {
		$editor->setNextArticle('135523');
		$editor->publish();
		var_dump(new ReflectionClass($editor));
	}

}

Run the test, and watch the magic happen in the output:

PHPUnit 3.6.11 by Sebastian Bergmann.

.object(ReflectionClass)#197 (1) {
  ["name"]=>
  string(6) "Editor"
}


Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

Our reflection class has a name property set to the original type of the $editor variable: Editor, but that's not much information. What about Editor's methods?

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		$editor->setNextArticle('135523');
		$editor->publish();

		$reflector = new ReflectionClass($editor);
		var_dump($reflector->getMethods());
	}

}

In this code, we assign the reflection class' instance to the $reflector variable so that we can now trigger its methods. ReflectionClass exposes a large set of methods that you can use to obtain an object's information. One of these methods is getMethods(), which returns an array containing each method's information.

PHPUnit 3.6.11 by Sebastian Bergmann.

.array(3) {
  [0]=>
  &object(ReflectionMethod)#196 (2) {
    ["name"]=>
    string(11) "__construct"
    ["class"]=>
    string(6) "Editor"
  }
  [1]=>
  &object(ReflectionMethod)#195 (2) {
    ["name"]=>
    string(14) "setNextArticle"
    ["class"]=>
    string(6) "Editor"
  }
  [2]=>
  &object(ReflectionMethod)#194 (2) {
    ["name"]=>
    string(7) "publish"
    ["class"]=>
    string(6) "Editor"
  }
}

Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

Another method, getProperties(), retrieves the properties (even private properties!) of the object:

PHPUnit 3.6.11 by Sebastian Bergmann.

.array(2) {
  [0]=>
  &object(ReflectionProperty)#196 (2) {
    ["name"]=>
    string(4) "name"
    ["class"]=>
    string(6) "Editor"
  }
  [1]=>
  &object(ReflectionProperty)#195 (2) {
    ["name"]=>
    string(9) "articleId"
    ["class"]=>
    string(6) "Editor"
  }
}

Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

The elements in the arrays returned from getMethod() and getProperties() are of type ReflectionMethod and ReflectionProperty, respectively; these objects are quite useful:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		$editor->setNextArticle('135523');
		$editor->publish(); // first call to publish()

		$reflector = new ReflectionClass($editor);
		$publishMethod = $reflector->getMethod('publish');
		$publishMethod->invoke($editor); // second call to publish()
	}

}

Here, we use getMethod() to retrieve a single method with the name of "publish"; the result of which is a ReflectionMethod object. Then, we call the invoke() method, passing it the $editor object, in order to execute the editor's publish() method a second time.

This process was simple in our case, because we already had an Editor object to pass to invoke(). We may have several Editor objects in some circumstances, giving us the luxury of choosing which object to use. In other circumstances, we may have no objects to work with, in which case we would need to obtain one from ReflectionClass.

Let's modify Editor's publish() method to demonstrate the double call:

// Editor.php

class Editor {

	[ ... ]

	public function publish() {
		// publish logic goes here
		echo ("HERE\n");
		return true;
	}

}

And the new output:

PHPUnit 3.6.11 by Sebastian Bergmann.

.HERE
HERE

Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

Manipulating Instance Data

We can also modify code at execution time. What about modifying a private variable that has no public setter? Let's add a method to Editor that retrieves the editor's name:

// Editor.php

class Editor {

	private $name;
	public $articleId;

	function __construct($name) {
		$this->name = $name;
	}

	[ ... ]

	function getEditorName() {
		return $this->name;
	}

}

This new method is called, getEditorName(), and simply returns the value from the private $name variable. The $name variable is set at creation time, and we have no public methods that let us change it. But we can access this variable using reflection. You might first try the more obvious approach:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		var_dump($editor->getEditorName());

		$reflector = new ReflectionClass($editor);
		$editorName = $reflector->getProperty('name');
		$editorName->getValue($editor);

	}

}

Even though this outputs the value at the var_dump() line, it throws an error when trying to retrieve the value with reflection:

PHPUnit 3.6.11 by Sebastian Bergmann.

Estring(8) "John Doe"


Time: 0 seconds, Memory: 2.50Mb

There was 1 error:

1) ReflectionTest::testItCanReflect
ReflectionException: Cannot access non-public member Editor::name

[...]/Reflection in PHP/Source/NetTuts.php:13
[...]/Reflection in PHP/Source/Tests/ReflectionTest.php:13
/usr/bin/phpunit:46

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.

In order to fix this problem, we need to ask the ReflectionProperty object to grant us access to the private variables and methods:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		var_dump($editor->getEditorName());

		$reflector = new ReflectionClass($editor);
		$editorName = $reflector->getProperty('name');
		$editorName->setAccessible(true);
		var_dump($editorName->getValue($editor));
	}

}

Calling setAccessible() and passing true does the trick:

PHPUnit 3.6.11 by Sebastian Bergmann.

.string(8) "John Doe"
string(8) "John Doe"


Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

As you can see, we've managed to read private variable. The first line of output is from the object's own getEditorName() method, and the second comes from reflection. But what about changing a private variable's value? Use the setValue() method:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		var_dump($editor->getEditorName());

		$reflector = new ReflectionClass($editor);
		$editorName = $reflector->getProperty('name');
		$editorName->setAccessible(true);
		$editorName->setValue($editor, 'Mark Twain');
		var_dump($editorName->getValue($editor));
	}

}

And that's it. This code changes "John Doe" to "Mark Twain".

PHPUnit 3.6.11 by Sebastian Bergmann.

.string(8) "John Doe"
string(10) "Mark Twain"


Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

Indirect Reflection Use

Some of PHP's built-in functionality indirectly uses reflection—one being the call_user_func() function.

The Callback

The call_user_func() function accepts an array: the first element pointing to an object, and the second a method's name. You can supply an optional parameter, which is then passed to the called method. For example:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		var_dump($editor->getEditorName());

		$reflector = new ReflectionClass($editor);
		$editorName = $reflector->getProperty('name');
		$editorName->setAccessible(true);
		$editorName->setValue($editor, 'Mark Twain');
		var_dump($editorName->getValue($editor));

		var_dump(call_user_func(array($editor, 'getEditorName')));
	}

}

The following output demonstrates that the code retrieves the proper value:

PHPUnit 3.6.11 by Sebastian Bergmann.

.string(8) "John Doe"
string(10) "Mark Twain"
string(10) "Mark Twain"


Time: 0 seconds, Memory: 2.25Mb

OK (1 test, 0 assertions)

Using a Variable's Value

Another example of indirect reflection is calling a method by the value contained within a variable, as opposed to directly calling it. For example:

// Nettuts.php

class Nettuts {

	function publishNextArticle($editor) {
		var_dump($editor->getEditorName());

		$reflector = new ReflectionClass($editor);
		$editorName = $reflector->getProperty('name');
		$editorName->setAccessible(true);
		$editorName->setValue($editor, 'Mark Twain');
		var_dump($editorName->getValue($editor));

		$methodName = 'getEditorName';
		var_dump($editor->$methodName());
	}

}

This code produces the same output as the previous example. PHP simply replaces the variable with the string it represents and calls the method. It even works when you want to create objects by using variables for class names.


When Should We Use Reflection?

Now that we've put the technical details behind us, when should we leverage reflection? Here are a few scenarios:

  • Dynamic typing is probably impossible without reflection.
  • Aspect Oriented Programming listens from method calls and places code around methods, all accomplished with reflection.
  • PHPUnit relies heavily on reflection, as do other mocking frameworks.
  • Web frameworks in general use reflection for different purposes. Some use it to initialize models, constructing objects for views and more. Laravel makes heavy use of reflection to inject dependencies.
  • Metaprogramming, like our last example, is hidden reflection.
  • Code analysis frameworks use reflection to understand your code.

Final Thoughts

As with any cool toy, use reflection, but don't abuse it. Reflection is costly when you inspect many objects, and it has the potential to complicate your project's architecture and design. I recommend that you make use of it only when it actually gives you an advantage, or when you have no other viable option.

Personally, I've only used reflection in a few instances, most commonly when using third party modules that lack documentation. I find myself frequently using code similar to the last example. It's easy to call the proper method, when your MVC responds with a variable containing "add" or "remove" values.

Thanks for reading!

Advertisement