Exploring the Power of ReflectionClass in PHP

Rakibul Islam
7 min readMar 2, 2023

--

ReflectionClass in PHP

As a curious developer diving deeper into the world of Dependency Injection, I stumbled upon a buzzword called ReflectionClass. Curious to know more about it, I dived deeper and discovered its amazing benefits. From dynamic analysis to code generation, ReflectionClass proved to be a powerful tool for debugging and testing.

In this article, we’ll explore what ReflectionClass is, how it can be used, and some of its benefits and use cases.

What is ReflectionClass?

ReflectionClass is a PHP built-in class that allows you to inspect the properties and methods of a class at runtime. It provides a way to dynamically analyze the structure of a class and its methods, and can be used to perform tasks such as:

  • Retrieving information about class methods and properties
  • Accessing and modifying class properties at runtime
  • Creating new instances of a class without using its constructor

ReflectionClass is part of PHP’s Reflection extension, which also includes other classes such as ReflectionFunction and ReflectionMethod.

How to Use ReflectionClass

Using ReflectionClass is relatively straightforward. Here’s an example of how to use it to inspect the properties and methods of a class:

class MyClass {
public $prop1;
protected $prop2;
private $prop3;

public function method1() {}
protected function method2() {}
private function method3() {}
}

$reflection = new ReflectionClass('MyClass');

// Get the class name
echo $reflection->getName();
// Output: MyClass

// Get the class properties
$properties = $reflection->getProperties();
foreach ($properties as $property) {
echo $property->getName() . ',';
}
// Output: prop1,prop2,prop3

// Get the class methods
$methods = $reflection->getMethods();
foreach ($methods as $method) {
echo $method->getName();
}
// Output: method1,method2,method3

In this example, we define a simple class called MyClass, with some properties and methods. We then create a new instance of ReflectionClass, passing the class name as a string. We can then use the ReflectionClass methods to inspect the class properties and methods.

Now that we have a slight understanding of what ReflectionClass is , let’s explore how it can be used to implement dependency injection. By leveraging the power of ReflectionClass, you can dynamically analyze and modify classes during runtime, making it easier to decouple dependencies from implementation, swap them out, and test classes in isolation.

Here’s an example to illustrate how dependency injection can be done using ReflectionClass:

class Foo
{
protected $bar;

public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}

class Bar
{
public function hello()
{
echo "Hello from Bar!";
}
}

$reflectionClass = new ReflectionClass('Foo');
$constructor = $reflectionClass->getConstructor();
$parameters = $constructor->getParameters();

$dependencies = [];

foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
$dependencies[] = new $dependency->name;
}

$foo = $reflectionClass->newInstanceArgs($dependencies);
$foo->bar->hello(); // Output: Hello from Bar!

In this example, we have two classes — Foo and Bar. Foo depends on Bar, and we want to inject the dependency using ReflectionClass.

First, we create a ReflectionClass object for Foo and get its constructor. We then loop through the constructor's parameters and get their respective class names. We create new instances of the dependencies using the name property of the ReflectionClass object.

Finally, we use the newInstanceArgs() method of the ReflectionClass object to instantiate Foo with its dependencies. We can then call the methods of Foo and its dependencies just as we would with any other PHP object.

That’s not all — ReflectionClass has several other use cases, ranging from code generation to dynamic dispatch. Lets explore -

Dynamic Analysis of Class Structure

One of the main use cases of ReflectionClass is that it allows you to dynamically analyze the structure of a class at runtime. This can be useful in situations where you need to perform tasks such as determining if a class has a specific method, or inspecting the properties of a class that you don’t have access to.

class MyClass {
public function foo() {}
private function bar() {}
}

$reflection = new ReflectionClass('MyClass');

// Check if class has method
if ($reflection->hasMethod('foo')) {
echo 'MyClass has method foo';
}

// Check if class has property
if ($reflection->hasProperty('prop')) {
echo 'MyClass has property prop';
}

In this example, we use ReflectionClass to dynamically check if the MyClass class has a method called foo and a property called prop.

Access to Private and Protected Class Properties and Methods

As you may already know, private and protected classes cannot be modified outside of the class, making it challenging to inspect and manipulate their properties and methods. However, ReflectionClass can be used to access and modify these classes during runtime, giving you more flexibility and control over your code. This can be useful in situations where you need to modify the behavior of a class that you don’t have direct access to.

class MyClass {
private $prop;

private function foo() {
echo $this->prop;
}
}

$reflection = new ReflectionClass('MyClass');
$instance = $reflection->newInstanceWithoutConstructor();

$prop = $reflection->getProperty('prop');
$prop->setAccessible(true);
$prop->setValue($instance, 'Hello World');

$foo = $reflection->getMethod('foo');
$foo->setAccessible(true);
$foo->invoke($instance);

In this example, we use ReflectionClass to access a private property and method of the MyClass class. We first create a new instance of the class without using its constructor, and then use the getProperty and getMethod methods to get access to the private property and method. We then use the setAccessible method to make them accessible, and finally use setValue to set the value of the property and invoke to call the method.

Creation of New Class Instances Without Using Constructors

ReflectionClass also allows you to create new instances of a class without using its constructor. This can be useful in situations where you need to create multiple instances of a class with different constructor arguments, or when you need to create a mock object for testing purposes. For example,

class MyClass {
public function __construct($foo, $bar) {
echo $foo . ' ' . $bar;
}
}

$reflection = new ReflectionClass('MyClass');
$instance = $reflection->newInstanceWithoutConstructor();
$instance->__construct('Hello', 'World');

Debugging and Testing

ReflectionClass can also be useful for debugging and testing purposes. It allows you to inspect the properties and methods of a class at runtime, which can be useful for identifying bugs and testing the behavior of a class. Let’s say you have a calculator class to add and subtract value,

class Calculator {
private $value;

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

public function add($number) {
$this->value += $number;
}

public function subtract($number) {
$this->value -= $number;
}

public function getValue() {
return $this->value;
}
}

// Create a new instance of the Calculator class
$calculator = new Calculator(10);

// Add 5 to the calculator's value
$calculator->add(5);

// Subtract 3 from the calculator's value
$calculator->subtract(3);

// Print the final value of the calculator
echo "The final value of the calculator is: " . $calculator->getValue() . "\n";

Now, let’s use ReflectionClass to inspect and debug the Calculator class.

$reflectionClass = new ReflectionClass('Calculator');

// Get the value of the $value property of the Calculator class
$reflectionProperty = $reflectionClass->getProperty('value');
$reflectionProperty->setAccessible(true);
$propertyValue = $reflectionProperty->getValue($calculator);

// Print the value of the $value property of the Calculator class
echo "The value of the 'value' property is: " . $propertyValue . "\n";

// Get the 'add' method of the Calculator class
$reflectionMethod = $reflectionClass->getMethod('add');

// Invoke the 'add' method with a parameter of 10
$reflectionMethod->invoke($calculator, 10);

// Print the updated value of the $value property of the Calculator class
echo "The value of the 'value' property after calling the 'add' method is: " . $calculator->getValue() . "\n";

In this example, we create a simple Calculator class with an add and subtract method. We then create a new instance of the class and call these methods to perform some calculations.

Next, we use ReflectionClass to inspect and debug the Calculator class. We get the value of the value property of the Calculator class, print it to the console, and then invoke the add method with a parameter of 10. Finally, we print the updated value of the value property to confirm that the method was invoked correctly.

Using ReflectionClass in this way can be helpful when debugging issues with your classes, especially when you need to access private or protected properties or methods.

Code Generation and Dynamic Dispatch

Finally, ReflectionClass can also be used for code generation and dynamic dispatch. For example, it can be used to dynamically generate code based on the structure of a class, or to dispatch method calls dynamically based on the class and method name.

class MyClass {
public function foo($arg) {
echo $arg;
}
}

$reflection = new ReflectionClass('MyClass');
$method = $reflection->getMethod('foo');

$arg = 'Hello World';
$method->invoke(new MyClass(), $arg);

In this example, we use ReflectionClass to dynamically invoke a method of the MyClass class with a dynamic argument. We first get the foo method using getMethod and then invoke it with a new instance of the class and a dynamic argument using invoke.

Moreover this can be used as documentation generator. laravel-apidoc-generator package is using ReflectionClass & ReflectionMethod extensively to get info about classes and methods doc blocks and then process them.

class Foo {
/**
* @return string
*/
public function getFooName(): string
{
return 'Foo';
}
}

$method = new ReflectionMethod('Foo', 'getFooName');
var_dump($method->getDocComment());
// Output:
string(33) "/**
* @return string
*/"

Conclusion

ReflectionClass is a powerful feature of PHP that provides dynamic access to class properties, methods, and metadata. It can be used for a wide range of purposes, from dependency injection to code generation to testing and debugging. By using ReflectionClass, you can write more flexible, modular, and maintainable PHP code, and gain a deeper understanding of how your code works.

While ReflectionClass can be a complex topic, with some practice and experimentation, you can learn to leverage its power to make your PHP development more efficient and effective. Whether you’re building a new PHP application from scratch or working with an existing codebase, taking the time to learn and use ReflectionClass can be a valuable investment in your development skills.

References:

  1. https://www.php.net/manual/en/book.reflection.php
  2. https://medium.com/tech-tajawal/introduction-to-php-reflection-api-4af07cc17db4

--

--

Rakibul Islam
Rakibul Islam

Written by Rakibul Islam

Passionate PHP Expert, Love to make things that make a difference! You can find me here, https://www.linkedin.com/in/rakibhstu/

Responses (1)