Advertisement
PHP

Reflection in PHP

by

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!

Related Posts
  • Code
    Web Development
    Test Code Coverage: From Myth to RealityXdebug wide retina preview
    Learn the myths about test code coverage and how to use it to analyze how much of your production code has been tested.Read More…
  • Code
    PHP
    SOLID: Part 4 - The Dependency Inversion Principle4 dip retina
    The Single Responsibility (SRP), Open/Closed (OCP), Liskov Substitution, Interface Segregation, and Dependency Inversion. Five agile principles that should guide you every time you write code.Read More…
  • Code
    PHP
    Setting Up a Local Mirror for Composer Packages With SatisComposer retina preview
    Installing all your PHP libraries with Composer is a great way to save time. But larger projects automatically tested and run at each commit to your software version control (SVC) system will take a long time to install all the required packages from the Internet. You want to run your tests as soon as possible through your continuous integration (CI) system so that you have fast feedback and quick reactions on failure. In this tutorial we will set up a local mirror to proxy all your packages required in your project's composer.json file. This will make our CI work much faster, install the packages over the local network or even hosted on the same machine, and make sure we have the specific versions of the packages always available.Read More…
  • Code
    PHP
    Validation and Exception Handling: From the UI to the BackendProcedural to oop php retina preview
    Sooner or later in your programming career you will be faced with the dilemma of validation and exception handling. This was the case with me and my team also. A couple or so years ago we reached a point when we had to take architectural actions to accommodate all the exceptional cases our quite large software project needed to handle. Below is a list of practices we came to value and apply when it comes to validation and exception handling.Read More…
  • Code
    PHP
    The Repository Design PatternRepository pattern retina preview
    The Repository Design Pattern, defined by Eric Evens in his Domain Driven Design book, is one of the most useful and most widely applicable design patterns ever invented. Any application has to work with persistence and with some kind of list of items. These can be users, products, networks, disks, or whatever your application is about. If you have a blog for example, you have to deal with lists of blog posts and lists of comments. The problem that all of these list management logics have in common is how to connect business logic, factories and persistence.Read More…
  • Code
    PHP
    Aspect-Oriented Programming in PHP with Go!Aop php go preview
    The concept of Aspect-Oriented Programming (AOP) is fairly new to PHP. There's currently no official AOP support in PHP, but there are some extensions and libraries which implement this feature. In this lesson, we'll use the Go! PHP library to learn AOP in PHP, and review when it can be helpful. Read More…