PHP - PHP Reflection API

Introduction

The PHP Reflection API is a built-in feature of PHP that allows a program to examine and inspect its own classes, objects, methods, properties, functions, parameters, and other program structures at runtime.

Normally, PHP programs know the structure of a class because the developer has written the class definition. Reflection provides a way to discover that information dynamically while the program is running.

For example, suppose a PHP application receives the name of a class as a string. Without Reflection, it can be difficult to determine:

  • What methods does the class contain?

  • What properties does it contain?

  • Which methods are public, private, or protected?

  • What parameters does a method accept?

  • What types do those parameters require?

  • Does the class extend another class?

  • Does it implement a particular interface?

  • What attributes are attached to the class or method?

The Reflection API provides classes and methods that can answer these questions programmatically.


1. Why Reflection Is Used

Reflection is particularly useful when an application needs to work with classes without knowing their complete structure in advance.

Consider this class:

class Student
{
    private string $name;
    public int $age;

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }
}

A normal program can directly call:

$student = new Student();

$student->setName("Rahul");

echo $student->getName();

However, suppose another program needs to discover the structure of Student dynamically.

It can use Reflection:

$reflection = new ReflectionClass(Student::class);

echo $reflection->getName();

Output:

Student

The program did not manually inspect the source code. PHP provided the class information through Reflection.


2. ReflectionClass

The most commonly used Reflection class is ReflectionClass.

It provides information about a PHP class.

Basic syntax:

$reflection = new ReflectionClass(ClassName::class);

Example:

class Employee
{
    public string $name;

    public function work(): void
    {
        echo "Employee is working";
    }
}

$reflection = new ReflectionClass(Employee::class);

echo $reflection->getName();

Output:

Employee

ReflectionClass can provide information about:

  • Class name

  • Parent class

  • Interfaces

  • Traits

  • Methods

  • Properties

  • Constants

  • Attributes

  • Modifiers

  • Constructor

  • Instantiability


3. Getting Class Name

The getName() method returns the name of the class.

class Product
{
}

$reflection = new ReflectionClass(Product::class);

echo $reflection->getName();

Output:

Product

This is useful when the class is supplied dynamically.


4. Checking Whether a Class Exists

Reflection can be combined with class_exists().

if (class_exists("Product")) {
    $reflection = new ReflectionClass("Product");

    echo $reflection->getName();
}

This prevents the application from attempting to reflect a class that does not exist.


5. Inspecting Class Methods

The getMethods() method returns information about the methods declared or inherited by a class.

Example:

class Calculator
{
    public function add()
    {
    }

    public function subtract()
    {
    }
}

$reflection = new ReflectionClass(Calculator::class);

$methods = $reflection->getMethods();

foreach ($methods as $method) {
    echo $method->getName() . PHP_EOL;
}

Output will include:

add
subtract

Each returned object is an instance of ReflectionMethod.


6. Inspecting a Specific Method

You can inspect one particular method using getMethod().

class User
{
    public function login(string $username, string $password): bool
    {
        return true;
    }
}

$reflection = new ReflectionClass(User::class);

$method = $reflection->getMethod("login");

echo $method->getName();

Output:

login

The ReflectionMethod object provides additional information about the method.


7. Inspecting Method Parameters

Reflection is particularly useful for discovering the parameters accepted by a method.

Example:

class User
{
    public function login(string $username, string $password): bool
    {
        return true;
    }
}

$reflection = new ReflectionClass(User::class);

$method = $reflection->getMethod("login");

$parameters = $method->getParameters();

foreach ($parameters as $parameter) {
    echo $parameter->getName() . PHP_EOL;
}

Output:

username
password

The application can therefore discover the parameter names without manually reading the source code.


8. Getting Parameter Types

Reflection can also determine the expected type of a parameter.

foreach ($method->getParameters() as $parameter) {
    echo $parameter->getName() . ": ";

    $type = $parameter->getType();

    if ($type !== null) {
        echo $type;
    }

    echo PHP_EOL;
}

Possible output:

username: string
password: string

This is useful for systems that need to automatically understand how a method should be called.


9. Inspecting Return Types

Reflection can also determine the return type of a method.

$method = $reflection->getMethod("login");

$returnType = $method->getReturnType();

echo $returnType;

Output:

bool

This allows a program to determine that the login() method is expected to return a Boolean value.


10. Inspecting Properties

The getProperties() method retrieves information about class properties.

Example:

class Customer
{
    private string $name;
    public int $age;
}

$reflection = new ReflectionClass(Customer::class);

$properties = $reflection->getProperties();

foreach ($properties as $property) {
    echo $property->getName() . PHP_EOL;
}

Output:

name
age

Each property is represented by a ReflectionProperty object.


11. Inspecting Property Visibility

Reflection can determine whether a property is public, protected, or private.

foreach ($reflection->getProperties() as $property) {

    echo $property->getName() . ": ";

    if ($property->isPublic()) {
        echo "Public";
    } elseif ($property->isProtected()) {
        echo "Protected";
    } elseif ($property->isPrivate()) {
        echo "Private";
    }

    echo PHP_EOL;
}

For the previous example, the output would be similar to:

name: Private
age: Public

This is useful for tools that need to understand class structure automatically.


12. Inspecting the Parent Class

Reflection can determine whether a class extends another class.

class Animal
{
}

class Dog extends Animal
{
}

$reflection = new ReflectionClass(Dog::class);

$parent = $reflection->getParentClass();

if ($parent !== false) {
    echo $parent->getName();
}

Output:

Animal

This allows applications to inspect inheritance relationships.


13. Checking Implemented Interfaces

A class can implement one or more interfaces.

interface Payment
{
}

class CreditCardPayment implements Payment
{
}

Reflection can determine which interfaces are implemented.

$reflection = new ReflectionClass(CreditCardPayment::class);

$interfaces = $reflection->getInterfaces();

foreach ($interfaces as $interface) {
    echo $interface->getName();
}

Output:

Payment

This can be useful in plugin systems and dependency-management systems.


14. Inspecting Traits

PHP classes can use traits.

trait Logger
{
    public function log()
    {
        echo "Logging";
    }
}

class Application
{
    use Logger;
}

Reflection can identify the traits used by the class.

$reflection = new ReflectionClass(Application::class);

$traits = $reflection->getTraits();

foreach ($traits as $trait) {
    echo $trait->getName();
}

Output:

Logger

15. Inspecting Class Modifiers

Reflection can determine whether a class is:

  • Abstract

  • Final

  • Instantiable

  • Internal

  • Anonymous

For example:

abstract class Animal
{
}

You can check:

$reflection = new ReflectionClass(Animal::class);

if ($reflection->isAbstract()) {
    echo "The class is abstract.";
}

Output:

The class is abstract.

Similarly:

if ($reflection->isFinal()) {
    echo "The class is final.";
}

16. Inspecting Constructors

Reflection can also inspect the constructor of a class.

class Employee
{
    public function __construct(
        string $name,
        int $id
    ) {
    }
}

You can retrieve the constructor:

$reflection = new ReflectionClass(Employee::class);

$constructor = $reflection->getConstructor();

if ($constructor !== null) {
    foreach ($constructor->getParameters() as $parameter) {
        echo $parameter->getName() . PHP_EOL;
    }
}

Output:

name
id

This capability is important in dependency injection systems.


17. Dynamically Creating Objects

Reflection can also be used to create objects.

For example:

class Product
{
    public function __construct(string $name)
    {
        echo "Product: " . $name;
    }
}

$reflection = new ReflectionClass(Product::class);

$product = $reflection->newInstance("Laptop");

The class is instantiated through Reflection rather than directly using:

new Product("Laptop");

This becomes useful when the class name and constructor information are determined dynamically.


18. ReflectionMethod

ReflectionMethod focuses specifically on methods.

Example:

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

$method = new ReflectionMethod(Calculator::class, "add");

echo $method->getName();

Output:

add

It can also provide:

  • Method parameters

  • Return type

  • Visibility

  • Static status

  • Abstract status

  • Final status

  • Attributes


19. Invoking Methods Dynamically

Reflection can invoke a method dynamically.

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

$calculator = new Calculator();

$method = new ReflectionMethod(Calculator::class, "add");

$result = $method->invoke($calculator, 10, 20);

echo $result;

Output:

30

Here, the method name can be determined dynamically rather than being directly written as:

$calculator->add(10, 20);

This capability is useful in frameworks, testing tools, command systems, and dynamic application architectures.


20. ReflectionFunction

Reflection is not limited to classes and methods. PHP also provides ReflectionFunction for inspecting functions.

Example:

function calculate(int $a, int $b): int
{
    return $a + $b;
}

$reflection = new ReflectionFunction("calculate");

echo $reflection->getName();

Output:

calculate

Parameters can also be inspected:

foreach ($reflection->getParameters() as $parameter) {
    echo $parameter->getName() . PHP_EOL;
}

Output:

a
b

21. ReflectionObject

ReflectionObject is used when you want to inspect a specific object.

Example:

class Customer
{
    public string $name = "John";
}

$customer = new Customer();

$reflection = new ReflectionObject($customer);

echo $reflection->getName();

Output:

Customer

It provides information about the actual object while it is running.


22. Reflection and Dependency Injection

One important practical use of Reflection is dependency injection.

Consider:

class Database
{
}

class UserRepository
{
    public function __construct(Database $database)
    {
    }
}

A dependency injection container can inspect the constructor:

$reflection = new ReflectionClass(UserRepository::class);

$constructor = $reflection->getConstructor();

foreach ($constructor->getParameters() as $parameter) {
    $type = $parameter->getType();

    echo $type;
}

The container can discover that UserRepository requires a Database object.

Frameworks can use this information to construct objects and supply their dependencies automatically.


23. Reflection in Testing

Testing frameworks can use Reflection to discover test methods or inspect classes.

For example, a testing system could examine a class and find methods that follow a particular naming convention.

$reflection = new ReflectionClass(MyTest::class);

foreach ($reflection->getMethods() as $method) {
    if (str_starts_with($method->getName(), "test")) {
        echo $method->getName() . PHP_EOL;
    }
}

A testing system could then execute the discovered methods.


24. Reflection in Frameworks

Many PHP frameworks and libraries need to understand application classes dynamically.

Reflection can help frameworks:

  • Discover dependencies

  • Inspect constructors

  • Identify methods

  • Read parameter types

  • Inspect attributes

  • Create objects

  • Invoke methods

  • Build dependency graphs

For example, a framework may receive:

class OrderController
{
    public function __construct(OrderService $service)
    {
    }
}

The framework can inspect the constructor and determine that OrderService needs to be supplied.

This reduces the amount of manual configuration required by developers.


25. Reflection and Attributes

Modern PHP supports attributes that can provide metadata.

For example:

#[Route("/users")]
class UserController
{
}

Reflection can inspect this attribute.

$reflection = new ReflectionClass(UserController::class);

$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    echo $attribute->getName();
}

Output:

Route

A framework can use this information to automatically configure routes, commands, services, or other application components.


26. ReflectionException

Reflection operations can produce exceptions when the requested class, method, or property does not exist.

Example:

try {
    $reflection = new ReflectionClass("UnknownClass");
} catch (ReflectionException $e) {
    echo "Reflection failed: " . $e->getMessage();
}

Using exception handling makes the application more reliable when working with dynamic class information.


27. Advantages of Reflection

Reflection provides several important advantages.

Dynamic Inspection

Programs can discover class and method information at runtime.

Framework Development

Reflection is useful when building dependency injection containers, routing systems, ORMs, testing frameworks, and plugin systems.

Reduced Manual Configuration

Applications can automatically discover dependencies and metadata.

Better Development Tools

IDEs, debugging tools, documentation generators, and testing tools can use reflection-like information to understand PHP code.

Flexible Object Creation

Objects can be created dynamically when the class and constructor information are not known beforehand.


28. Limitations of Reflection

Reflection should not be used everywhere.

It can make applications more complex because the program becomes dependent on dynamically discovered information.

There can also be performance overhead when Reflection is repeatedly performed during application execution.

For example, repeatedly inspecting the same class is generally unnecessary. A framework may therefore cache Reflection information.

Reflection can also make code harder to understand if it replaces straightforward method calls and object creation without a genuine need.


29. Reflection Compared with Normal PHP Code

Normal approach:

$user = new User();

$user->login("rahul", "12345");

The developer already knows the class and method.

Reflection-based approach:

$reflection = new ReflectionClass(User::class);

$method = $reflection->getMethod("login");

$result = $method->invoke(
    $user,
    "rahul",
    "12345"
);

The second approach is more dynamic, but it is also more complex.

Therefore, Reflection is most valuable when the application genuinely needs runtime inspection or dynamic behavior.


30. Complete Example

The following example demonstrates several Reflection features together:

class Employee
{
    private string $name;

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

    public function greet(string $message): string
    {
        return $message . ", " . $this->name;
    }
}

$reflection = new ReflectionClass(Employee::class);

echo "Class: " . $reflection->getName() . PHP_EOL;

echo "Properties:" . PHP_EOL;

foreach ($reflection->getProperties() as $property) {
    echo $property->getName() . PHP_EOL;
}

echo "Methods:" . PHP_EOL;

foreach ($reflection->getMethods() as $method) {
    echo $method->getName() . PHP_EOL;
}

$constructor = $reflection->getConstructor();

if ($constructor !== null) {
    echo "Constructor Parameters:" . PHP_EOL;

    foreach ($constructor->getParameters() as $parameter) {
        echo $parameter->getName() . PHP_EOL;
    }
}

This program dynamically discovers information about the Employee class.

It can identify:

Class: Employee
Properties:
name
Methods:
__construct
greet
Constructor Parameters:
name

The important point is that the program is obtaining this structural information through the Reflection API rather than manually maintaining a separate description of the class.


Conclusion

The PHP Reflection API provides a powerful mechanism for examining PHP classes, objects, methods, properties, functions, parameters, return types, interfaces, traits, constructors, and attributes at runtime.

The major Reflection classes include:

Reflection Class Purpose
ReflectionClass Inspects classes
ReflectionMethod Inspects class methods
ReflectionProperty Inspects class properties
ReflectionFunction Inspects functions
ReflectionObject Inspects objects
ReflectionParameter Inspects function or method parameters

Reflection is especially important when developing frameworks, dependency injection containers, testing systems, plugin architectures, routing systems, object factories, and developer tools.

For ordinary application code, direct class and method calls are usually simpler. Reflection becomes valuable when the program needs to discover or manipulate PHP structures dynamically at runtime.