Reflection provides a way to examine the properties and methods of classes, as well as their visibility and other attributes. By using reflection, developers can create dynamic applications that adapt based on the structure of the code at runtime. This article will cover the following key aspects of PHP Reflection:

  1. Basic Reflection Classes
  2. Inspecting Class Properties and Methods
  3. Using Reflection for Dependency Injection
  4. Creating Annotations with Reflection

1. Basic Reflection Classes

PHP provides several core classes within the Reflection namespace, including ReflectionClass, ReflectionMethod, ReflectionProperty, and ReflectionFunction. Each of these classes serves a specific purpose in examining different aspects of PHP code.

Here’s a simple example of how to use ReflectionClass to inspect a class:

class SampleClass {
    private $property;

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

    public function getProperty() {
        return $this->property;
    }
}

$reflectionClass = new ReflectionClass('SampleClass');
echo "Class Name: " . $reflectionClass->getName() . PHP_EOL;
echo "Is Instantiable: " . ($reflectionClass->isInstantiable() ? 'Yes' : 'No') . PHP_EOL;

2. Inspecting Class Properties and Methods

Reflection allows you to examine the properties and methods of a class, including their visibility (public, private, protected) and other attributes. Here’s how you can retrieve and display this information:

$reflectionClass = new ReflectionClass('SampleClass');

// Inspecting properties
$properties = $reflectionClass->getProperties();
echo "Properties:\n";
foreach ($properties as $property) {
    echo $property->getName() . " - Visibility: " . ($property->isPublic() ? 'Public' : ($property->isProtected() ? 'Protected' : 'Private')) . PHP_EOL;
}

// Inspecting methods
$methods = $reflectionClass->getMethods();
echo "\nMethods:\n";
foreach ($methods as $method) {
    echo $method->getName() . " - Visibility: " . ($method->isPublic() ? 'Public' : ($method->isProtected() ? 'Protected' : 'Private')) . PHP_EOL;
}

3. Using Reflection for Dependency Injection

Reflection can also be used to facilitate dependency injection in your applications. By automatically resolving dependencies, you can create more flexible and maintainable code. Here’s an example of how to achieve this:

class Database {
    public function connect() {
        return "Database connected!";
    }
}

class UserService {
    private $database;

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

    public function getUser() {
        return $this->database->connect();
    }
}

function createInstance($className) {
    $reflectionClass = new ReflectionClass($className);
    $constructor = $reflectionClass->getConstructor();
    
    if (is_null($constructor)) {
        return $reflectionClass->newInstance();
    }

    $params = $constructor->getParameters();
    $dependencies = [];
    
    foreach ($params as $param) {
        $dependencyClass = $param->getClass()->name;
        $dependencies[] = createInstance($dependencyClass);
    }
    
    return $reflectionClass->newInstanceArgs($dependencies);
}

$userService = createInstance(UserService::class);
echo $userService->getUser() . PHP_EOL;

4. Creating Annotations with Reflection

Annotations can be a powerful way to add metadata to your classes and methods. PHP does not have built-in support for annotations, but with reflection, you can simulate this functionality. Here’s a simple implementation:

/**
 * @Route("/user")
 */
class UserController {
    public function index() {
        return "User index";
    }
}

function getAnnotations($className) {
    $reflectionClass = new ReflectionClass($className);
    $docComment = $reflectionClass->getDocComment();
    
    preg_match_all('/@(\w+)\s*(.*)/', $docComment, $matches);
    
    $annotations = [];
    foreach ($matches[1] as $key => $name) {
        $annotations[$name] = trim($matches[2][$key]);
    }
    
    return $annotations;
}

$annotations = getAnnotations(UserController::class);
print_r($annotations);

Conclusion

The Reflection API in PHP provides powerful tools for introspection and dynamic behavior in your applications. By leveraging reflection, you can create flexible and maintainable code, automate dependency resolution, and implement custom annotations. As you explore these advanced concepts, consider how reflection can enhance your development practices and lead to more robust applications.

Learn more with useful resources