Navigation

Php

PHP's Reflection API: Dynamic Code Generation and Analysis (Complete Guide 2025)

Master PHP Reflection API for dynamic code analysis, runtime inspection, and automated code generation. Learn advanced techniques with practical examples.

Table Of Contents

Introduction

PHP's Reflection API is one of the language's most powerful yet underutilized features, enabling developers to inspect and manipulate code at runtime. Whether you're building frameworks, creating automated testing tools, or developing dynamic applications that adapt based on their own structure, the Reflection API provides the foundation for sophisticated metaprogramming techniques.

This comprehensive guide will take you from basic reflection concepts to advanced dynamic code generation patterns, showing you how to leverage PHP's introspection capabilities to build more flexible, maintainable, and intelligent applications.

Understanding PHP Reflection Fundamentals

What is Reflection?

Reflection in PHP allows programs to examine their own structure and behavior at runtime. It provides a way to inspect classes, methods, properties, functions, and even extensions without executing them. Think of it as a mirror that lets your code look at itself and understand its own composition.

Core Reflection Classes

PHP's Reflection API consists of several core classes:

<?php
// Core reflection classes
$reflectionClasses = [
    'ReflectionClass',      // Inspect classes
    'ReflectionMethod',     // Inspect methods
    'ReflectionProperty',   // Inspect properties
    'ReflectionFunction',   // Inspect functions
    'ReflectionParameter',  // Inspect parameters
    'ReflectionExtension',  // Inspect extensions
    'ReflectionObject',     // Inspect objects
    'ReflectionType',       // Inspect type hints
    'ReflectionAttribute'   // Inspect attributes (PHP 8+)
];

foreach ($reflectionClasses as $class) {
    if (class_exists($class)) {
        echo "✓ $class available\n";
    }
}
?>

Basic Reflection Operations

<?php
class ExampleClass {
    private string $privateProperty = 'secret';
    protected int $protectedProperty = 42;
    public array $publicProperty = ['a', 'b', 'c'];
    
    public function __construct(string $name = 'default') {
        $this->name = $name;
    }
    
    public function publicMethod(string $param): string {
        return "Hello, $param!";
    }
    
    private function privateMethod(): void {
        echo "This is private\n";
    }
    
    protected static function staticMethod(): string {
        return "Static method called";
    }
}

// Basic class reflection
$reflection = new ReflectionClass(ExampleClass::class);

echo "Class name: " . $reflection->getName() . "\n";
echo "Short name: " . $reflection->getShortName() . "\n";
echo "Namespace: " . $reflection->getNamespaceName() . "\n";
echo "Is instantiable: " . ($reflection->isInstantiable() ? 'Yes' : 'No') . "\n";
echo "Is abstract: " . ($reflection->isAbstract() ? 'Yes' : 'No') . "\n";
echo "Is final: " . ($reflection->isFinal() ? 'Yes' : 'No') . "\n";
?>

Advanced Class Inspection Techniques

Complete Class Analysis Tool

<?php
class ClassAnalyzer {
    private ReflectionClass $reflection;
    private array $analysis = [];
    
    public function __construct(string $className) {
        if (!class_exists($className)) {
            throw new InvalidArgumentException("Class $className does not exist");
        }
        
        $this->reflection = new ReflectionClass($className);
        $this->performAnalysis();
    }
    
    private function performAnalysis(): void {
        $this->analysis = [
            'basic_info' => $this->getBasicInfo(),
            'inheritance' => $this->getInheritanceInfo(),
            'properties' => $this->getPropertiesInfo(),
            'methods' => $this->getMethodsInfo(),
            'constants' => $this->getConstantsInfo(),
            'traits' => $this->getTraitsInfo(),
            'interfaces' => $this->getInterfacesInfo(),
            'attributes' => $this->getAttributesInfo(),
            'metrics' => $this->calculateMetrics()
        ];
    }
    
    private function getBasicInfo(): array {
        return [
            'name' => $this->reflection->getName(),
            'short_name' => $this->reflection->getShortName(),
            'namespace' => $this->reflection->getNamespaceName(),
            'filename' => $this->reflection->getFileName(),
            'start_line' => $this->reflection->getStartLine(),
            'end_line' => $this->reflection->getEndLine(),
            'doc_comment' => $this->reflection->getDocComment(),
            'modifiers' => [
                'abstract' => $this->reflection->isAbstract(),
                'final' => $this->reflection->isFinal(),
                'instantiable' => $this->reflection->isInstantiable(),
                'cloneable' => $this->reflection->isCloneable(),
                'iterable' => $this->reflection->isIterable()
            ]
        ];
    }
    
    private function getInheritanceInfo(): array {
        $info = [
            'parent_class' => null,
            'parent_classes' => [],
            'implements' => [],
            'uses_traits' => []
        ];
        
        // Parent class
        $parent = $this->reflection->getParentClass();
        if ($parent) {
            $info['parent_class'] = $parent->getName();
            
            // Get all parent classes
            while ($parent) {
                $info['parent_classes'][] = $parent->getName();
                $parent = $parent->getParentClass();
            }
        }
        
        // Interfaces
        foreach ($this->reflection->getInterfaces() as $interface) {
            $info['implements'][] = $interface->getName();
        }
        
        // Traits
        foreach ($this->reflection->getTraits() as $trait) {
            $info['uses_traits'][] = $trait->getName();
        }
        
        return $info;
    }
    
    private function getPropertiesInfo(): array {
        $properties = [];
        
        foreach ($this->reflection->getProperties() as $property) {
            $propertyInfo = [
                'name' => $property->getName(),
                'visibility' => $this->getVisibility($property),
                'static' => $property->isStatic(),
                'default_value' => null,
                'type' => null,
                'doc_comment' => $property->getDocComment(),
                'attributes' => $this->getPropertyAttributes($property)
            ];
            
            // Get type information
            if ($property->hasType()) {
                $type = $property->getType();
                $propertyInfo['type'] = $this->getTypeInfo($type);
            }
            
            // Get default value
            if ($property->hasDefaultValue()) {
                $propertyInfo['default_value'] = $property->getDefaultValue();
            }
            
            $properties[] = $propertyInfo;
        }
        
        return $properties;
    }
    
    private function getMethodsInfo(): array {
        $methods = [];
        
        foreach ($this->reflection->getMethods() as $method) {
            $methodInfo = [
                'name' => $method->getName(),
                'visibility' => $this->getVisibility($method),
                'static' => $method->isStatic(),
                'abstract' => $method->isAbstract(),
                'final' => $method->isFinal(),
                'constructor' => $method->isConstructor(),
                'destructor' => $method->isDestructor(),
                'parameters' => $this->getParametersInfo($method),
                'return_type' => null,
                'doc_comment' => $method->getDocComment(),
                'attributes' => $this->getMethodAttributes($method),
                'declaring_class' => $method->getDeclaringClass()->getName()
            ];
            
            // Return type
            if ($method->hasReturnType()) {
                $returnType = $method->getReturnType();
                $methodInfo['return_type'] = $this->getTypeInfo($returnType);
            }
            
            $methods[] = $methodInfo;
        }
        
        return $methods;
    }
    
    private function getParametersInfo(ReflectionMethod $method): array {
        $parameters = [];
        
        foreach ($method->getParameters() as $parameter) {
            $paramInfo = [
                'name' => $parameter->getName(),
                'position' => $parameter->getPosition(),
                'optional' => $parameter->isOptional(),
                'default_value' => null,
                'type' => null,
                'variadic' => $parameter->isVariadic(),
                'passed_by_reference' => $parameter->isPassedByReference(),
                'attributes' => $this->getParameterAttributes($parameter)
            ];
            
            // Type information
            if ($parameter->hasType()) {
                $type = $parameter->getType();
                $paramInfo['type'] = $this->getTypeInfo($type);
            }
            
            // Default value
            if ($parameter->isDefaultValueAvailable()) {
                $paramInfo['default_value'] = $parameter->getDefaultValue();
            }
            
            $parameters[] = $paramInfo;
        }
        
        return $parameters;
    }
    
    private function getConstantsInfo(): array {
        $constants = [];
        
        foreach ($this->reflection->getConstants() as $name => $value) {
            $constants[] = [
                'name' => $name,
                'value' => $value,
                'visibility' => 'public' // Default for class constants
            ];
        }
        
        return $constants;
    }
    
    private function getTraitsInfo(): array {
        $traits = [];
        
        foreach ($this->reflection->getTraits() as $trait) {
            $traits[] = [
                'name' => $trait->getName(),
                'filename' => $trait->getFileName(),
                'methods' => array_map(fn($m) => $m->getName(), $trait->getMethods())
            ];
        }
        
        return $traits;
    }
    
    private function getInterfacesInfo(): array {
        $interfaces = [];
        
        foreach ($this->reflection->getInterfaces() as $interface) {
            $interfaces[] = [
                'name' => $interface->getName(),
                'methods' => array_map(fn($m) => $m->getName(), $interface->getMethods())
            ];
        }
        
        return $interfaces;
    }
    
    private function getAttributesInfo(): array {
        if (PHP_VERSION_ID < 80000) {
            return [];
        }
        
        $attributes = [];
        
        foreach ($this->reflection->getAttributes() as $attribute) {
            $attributes[] = [
                'name' => $attribute->getName(),
                'arguments' => $attribute->getArguments(),
                'target' => 'class'
            ];
        }
        
        return $attributes;
    }
    
    private function calculateMetrics(): array {
        $methods = $this->reflection->getMethods();
        $properties = $this->reflection->getProperties();
        
        return [
            'total_methods' => count($methods),
            'public_methods' => count(array_filter($methods, fn($m) => $m->isPublic())),
            'private_methods' => count(array_filter($methods, fn($m) => $m->isPrivate())),
            'protected_methods' => count(array_filter($methods, fn($m) => $m->isProtected())),
            'static_methods' => count(array_filter($methods, fn($m) => $m->isStatic())),
            'total_properties' => count($properties),
            'public_properties' => count(array_filter($properties, fn($p) => $p->isPublic())),
            'private_properties' => count(array_filter($properties, fn($p) => $p->isPrivate())),
            'protected_properties' => count(array_filter($properties, fn($p) => $p->isProtected())),
            'static_properties' => count(array_filter($properties, fn($p) => $p->isStatic())),
            'lines_of_code' => $this->reflection->getEndLine() - $this->reflection->getStartLine() + 1
        ];
    }
    
    private function getVisibility($reflector): string {
        if ($reflector->isPublic()) return 'public';
        if ($reflector->isProtected()) return 'protected';
        if ($reflector->isPrivate()) return 'private';
        return 'unknown';
    }
    
    private function getTypeInfo($type): array {
        $info = [
            'name' => (string)$type,
            'builtin' => $type->isBuiltin(),
            'nullable' => false
        ];
        
        if (method_exists($type, 'allowsNull')) {
            $info['nullable'] = $type->allowsNull();
        }
        
        return $info;
    }
    
    private function getPropertyAttributes(ReflectionProperty $property): array {
        if (PHP_VERSION_ID < 80000) {
            return [];
        }
        
        $attributes = [];
        foreach ($property->getAttributes() as $attribute) {
            $attributes[] = [
                'name' => $attribute->getName(),
                'arguments' => $attribute->getArguments()
            ];
        }
        
        return $attributes;
    }
    
    private function getMethodAttributes(ReflectionMethod $method): array {
        if (PHP_VERSION_ID < 80000) {
            return [];
        }
        
        $attributes = [];
        foreach ($method->getAttributes() as $attribute) {
            $attributes[] = [
                'name' => $attribute->getName(),
                'arguments' => $attribute->getArguments()
            ];
        }
        
        return $attributes;
    }
    
    private function getParameterAttributes(ReflectionParameter $parameter): array {
        if (PHP_VERSION_ID < 80000) {
            return [];
        }
        
        $attributes = [];
        foreach ($parameter->getAttributes() as $attribute) {
            $attributes[] = [
                'name' => $attribute->getName(),
                'arguments' => $attribute->getArguments()
            ];
        }
        
        return $attributes;
    }
    
    public function getAnalysis(): array {
        return $this->analysis;
    }
    
    public function exportToJson(): string {
        return json_encode($this->analysis, JSON_PRETTY_PRINT);
    }
    
    public function generateReport(): string {
        $report = "=== CLASS ANALYSIS REPORT ===\n\n";
        
        $basic = $this->analysis['basic_info'];
        $report .= "Class: {$basic['name']}\n";
        $report .= "File: {$basic['filename']}\n";
        $report .= "Lines: {$basic['start_line']}-{$basic['end_line']}\n\n";
        
        $metrics = $this->analysis['metrics'];
        $report .= "METRICS:\n";
        $report .= "  Methods: {$metrics['total_methods']} (Public: {$metrics['public_methods']}, Private: {$metrics['private_methods']}, Protected: {$metrics['protected_methods']})\n";
        $report .= "  Properties: {$metrics['total_properties']} (Public: {$metrics['public_properties']}, Private: {$metrics['private_properties']}, Protected: {$metrics['protected_properties']})\n";
        $report .= "  Lines of Code: {$metrics['lines_of_code']}\n\n";
        
        if (!empty($this->analysis['inheritance']['parent_class'])) {
            $report .= "INHERITANCE:\n";
            $report .= "  Parent: {$this->analysis['inheritance']['parent_class']}\n";
        }
        
        if (!empty($this->analysis['inheritance']['implements'])) {
            $report .= "  Implements: " . implode(', ', $this->analysis['inheritance']['implements']) . "\n";
        }
        
        if (!empty($this->analysis['inheritance']['uses_traits'])) {
            $report .= "  Uses Traits: " . implode(', ', $this->analysis['inheritance']['uses_traits']) . "\n";
        }
        
        return $report;
    }
}

// Usage example
$analyzer = new ClassAnalyzer(DateTime::class);
echo $analyzer->generateReport();
?>

Dynamic Property and Method Access

Runtime Property Manipulation

<?php
class DynamicPropertyManager {
    public static function getPropertyValue(object $object, string $propertyName): mixed {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasProperty($propertyName)) {
            throw new InvalidArgumentException("Property $propertyName does not exist");
        }
        
        $property = $reflection->getProperty($propertyName);
        
        // Make property accessible if it's private or protected
        if (!$property->isPublic()) {
            $property->setAccessible(true);
        }
        
        return $property->getValue($object);
    }
    
    public static function setPropertyValue(object $object, string $propertyName, mixed $value): void {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasProperty($propertyName)) {
            throw new InvalidArgumentException("Property $propertyName does not exist");
        }
        
        $property = $reflection->getProperty($propertyName);
        
        // Make property accessible if it's private or protected
        if (!$property->isPublic()) {
            $property->setAccessible(true);
        }
        
        $property->setValue($object, $value);
    }
    
    public static function hasProperty(object $object, string $propertyName): bool {
        $reflection = new ReflectionClass($object);
        return $reflection->hasProperty($propertyName);
    }
    
    public static function getPropertyMetadata(object $object, string $propertyName): array {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasProperty($propertyName)) {
            throw new InvalidArgumentException("Property $propertyName does not exist");
        }
        
        $property = $reflection->getProperty($propertyName);
        
        return [
            'name' => $property->getName(),
            'public' => $property->isPublic(),
            'private' => $property->isPrivate(),
            'protected' => $property->isProtected(),
            'static' => $property->isStatic(),
            'has_type' => $property->hasType(),
            'type' => $property->hasType() ? (string)$property->getType() : null,
            'has_default_value' => $property->hasDefaultValue(),
            'default_value' => $property->hasDefaultValue() ? $property->getDefaultValue() : null,
            'doc_comment' => $property->getDocComment(),
            'declaring_class' => $property->getDeclaringClass()->getName()
        ];
    }
    
    public static function copyProperties(object $source, object $target, array $propertyNames = []): void {
        $sourceReflection = new ReflectionClass($source);
        $targetReflection = new ReflectionClass($target);
        
        $properties = empty($propertyNames) 
            ? $sourceReflection->getProperties() 
            : array_filter(
                $sourceReflection->getProperties(),
                fn($p) => in_array($p->getName(), $propertyNames)
            );
        
        foreach ($properties as $sourceProperty) {
            $propertyName = $sourceProperty->getName();
            
            if (!$targetReflection->hasProperty($propertyName)) {
                continue;
            }
            
            $targetProperty = $targetReflection->getProperty($propertyName);
            
            // Make properties accessible
            if (!$sourceProperty->isPublic()) {
                $sourceProperty->setAccessible(true);
            }
            if (!$targetProperty->isPublic()) {
                $targetProperty->setAccessible(true);
            }
            
            $value = $sourceProperty->getValue($source);
            $targetProperty->setValue($target, $value);
        }
    }
}

// Example usage
class TestClass {
    private string $privateProperty = 'secret';
    protected int $protectedProperty = 42;
    public array $publicProperty = ['a', 'b', 'c'];
}

$object = new TestClass();

// Get private property value
$secretValue = DynamicPropertyManager::getPropertyValue($object, 'privateProperty');
echo "Private property value: $secretValue\n";

// Set private property value
DynamicPropertyManager::setPropertyValue($object, 'privateProperty', 'new secret');
$newValue = DynamicPropertyManager::getPropertyValue($object, 'privateProperty');
echo "Updated private property: $newValue\n";

// Get property metadata
$metadata = DynamicPropertyManager::getPropertyMetadata($object, 'privateProperty');
print_r($metadata);
?>

Dynamic Method Invocation

<?php
class DynamicMethodInvoker {
    public static function invokeMethod(object $object, string $methodName, array $arguments = []): mixed {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasMethod($methodName)) {
            throw new InvalidArgumentException("Method $methodName does not exist");
        }
        
        $method = $reflection->getMethod($methodName);
        
        // Make method accessible if it's private or protected
        if (!$method->isPublic()) {
            $method->setAccessible(true);
        }
        
        return $method->invokeArgs($object, $arguments);
    }
    
    public static function invokeStaticMethod(string $className, string $methodName, array $arguments = []): mixed {
        $reflection = new ReflectionClass($className);
        
        if (!$reflection->hasMethod($methodName)) {
            throw new InvalidArgumentException("Method $methodName does not exist");
        }
        
        $method = $reflection->getMethod($methodName);
        
        if (!$method->isStatic()) {
            throw new InvalidArgumentException("Method $methodName is not static");
        }
        
        // Make method accessible if it's private or protected
        if (!$method->isPublic()) {
            $method->setAccessible(true);
        }
        
        return $method->invokeArgs(null, $arguments);
    }
    
    public static function getMethodSignature(object $object, string $methodName): array {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasMethod($methodName)) {
            throw new InvalidArgumentException("Method $methodName does not exist");
        }
        
        $method = $reflection->getMethod($methodName);
        
        $parameters = [];
        foreach ($method->getParameters() as $param) {
            $paramInfo = [
                'name' => $param->getName(),
                'type' => $param->hasType() ? (string)$param->getType() : 'mixed',
                'optional' => $param->isOptional(),
                'default' => $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null,
                'variadic' => $param->isVariadic(),
                'by_reference' => $param->isPassedByReference()
            ];
            
            $parameters[] = $paramInfo;
        }
        
        return [
            'name' => $method->getName(),
            'return_type' => $method->hasReturnType() ? (string)$method->getReturnType() : 'mixed',
            'parameters' => $parameters,
            'visibility' => $method->isPublic() ? 'public' : ($method->isProtected() ? 'protected' : 'private'),
            'static' => $method->isStatic(),
            'abstract' => $method->isAbstract(),
            'final' => $method->isFinal()
        ];
    }
    
    public static function createMethodProxy(object $object, string $methodName): Closure {
        $reflection = new ReflectionClass($object);
        $method = $reflection->getMethod($methodName);
        
        if (!$method->isPublic()) {
            $method->setAccessible(true);
        }
        
        return function(...$args) use ($object, $method) {
            return $method->invokeArgs($object, $args);
        };
    }
}

// Example usage
class Calculator {
    private function add(int $a, int $b): int {
        return $a + $b;
    }
    
    protected function multiply(int $a, int $b): int {
        return $a * $b;
    }
    
    public static function divide(float $a, float $b): float {
        if ($b === 0.0) {
            throw new DivisionByZeroError('Division by zero');
        }
        return $a / $b;
    }
}

$calculator = new Calculator();

// Invoke private method
$result = DynamicMethodInvoker::invokeMethod($calculator, 'add', [5, 3]);
echo "5 + 3 = $result\n";

// Invoke static method
$result = DynamicMethodInvoker::invokeStaticMethod(Calculator::class, 'divide', [10, 2]);
echo "10 / 2 = $result\n";

// Get method signature
$signature = DynamicMethodInvoker::getMethodSignature($calculator, 'multiply');
print_r($signature);

// Create method proxy
$addProxy = DynamicMethodInvoker::createMethodProxy($calculator, 'add');
echo "Proxy result: " . $addProxy(10, 20) . "\n";
?>

Code Generation and Dynamic Class Creation

Dynamic Class Builder

<?php
class DynamicClassBuilder {
    private string $className;
    private string $namespace = '';
    private string $extends = '';
    private array $implements = [];
    private array $traits = [];
    private array $properties = [];
    private array $methods = [];
    private array $constants = [];
    private string $docComment = '';
    
    public function __construct(string $className) {
        $this->className = $className;
    }
    
    public function setNamespace(string $namespace): self {
        $this->namespace = $namespace;
        return $this;
    }
    
    public function extends(string $parentClass): self {
        $this->extends = $parentClass;
        return $this;
    }
    
    public function implements(string ...$interfaces): self {
        $this->implements = array_merge($this->implements, $interfaces);
        return $this;
    }
    
    public function useTrait(string ...$traits): self {
        $this->traits = array_merge($this->traits, $traits);
        return $this;
    }
    
    public function addProperty(string $name, string $visibility = 'private', ?string $type = null, mixed $defaultValue = null): self {
        $this->properties[$name] = [
            'visibility' => $visibility,
            'type' => $type,
            'default' => $defaultValue,
            'static' => false
        ];
        return $this;
    }
    
    public function addStaticProperty(string $name, string $visibility = 'private', ?string $type = null, mixed $defaultValue = null): self {
        $this->properties[$name] = [
            'visibility' => $visibility,
            'type' => $type,
            'default' => $defaultValue,
            'static' => true
        ];
        return $this;
    }
    
    public function addMethod(string $name, string $body, string $visibility = 'public', ?string $returnType = null, array $parameters = []): self {
        $this->methods[$name] = [
            'visibility' => $visibility,
            'return_type' => $returnType,
            'parameters' => $parameters,
            'body' => $body,
            'static' => false,
            'abstract' => false,
            'final' => false
        ];
        return $this;
    }
    
    public function addStaticMethod(string $name, string $body, string $visibility = 'public', ?string $returnType = null, array $parameters = []): self {
        $this->methods[$name] = [
            'visibility' => $visibility,
            'return_type' => $returnType,
            'parameters' => $parameters,
            'body' => $body,
            'static' => true,
            'abstract' => false,
            'final' => false
        ];
        return $this;
    }
    
    public function addConstant(string $name, mixed $value): self {
        $this->constants[$name] = $value;
        return $this;
    }
    
    public function setDocComment(string $docComment): self {
        $this->docComment = $docComment;
        return $this;
    }
    
    public function generateCode(): string {
        $code = "<?php\n\n";
        
        // Namespace
        if (!empty($this->namespace)) {
            $code .= "namespace {$this->namespace};\n\n";
        }
        
        // Class declaration
        if (!empty($this->docComment)) {
            $code .= $this->docComment . "\n";
        }
        
        $code .= "class {$this->className}";
        
        if (!empty($this->extends)) {
            $code .= " extends {$this->extends}";
        }
        
        if (!empty($this->implements)) {
            $code .= " implements " . implode(', ', $this->implements);
        }
        
        $code .= "\n{\n";
        
        // Traits
        foreach ($this->traits as $trait) {
            $code .= "    use {$trait};\n";
        }
        
        if (!empty($this->traits)) {
            $code .= "\n";
        }
        
        // Constants
        foreach ($this->constants as $name => $value) {
            $valueStr = is_string($value) ? "'{$value}'" : var_export($value, true);
            $code .= "    public const {$name} = {$valueStr};\n";
        }
        
        if (!empty($this->constants)) {
            $code .= "\n";
        }
        
        // Properties
        foreach ($this->properties as $name => $config) {
            $code .= "    {$config['visibility']}";
            
            if ($config['static']) {
                $code .= " static";
            }
            
            if ($config['type']) {
                $code .= " {$config['type']}";
            }
            
            $code .= " \${$name}";
            
            if ($config['default'] !== null) {
                $defaultStr = is_string($config['default']) ? "'{$config['default']}'" : var_export($config['default'], true);
                $code .= " = {$defaultStr}";
            }
            
            $code .= ";\n";
        }
        
        if (!empty($this->properties)) {
            $code .= "\n";
        }
        
        // Methods
        foreach ($this->methods as $name => $config) {
            $code .= "    {$config['visibility']}";
            
            if ($config['static']) {
                $code .= " static";
            }
            
            $code .= " function {$name}(";
            
            // Parameters
            $paramStrings = [];
            foreach ($config['parameters'] as $param) {
                $paramStr = '';
                
                if (isset($param['type'])) {
                    $paramStr .= $param['type'] . ' ';
                }
                
                $paramStr .= '$' . $param['name'];
                
                if (isset($param['default'])) {
                    $defaultStr = is_string($param['default']) ? "'{$param['default']}'" : var_export($param['default'], true);
                    $paramStr .= " = {$defaultStr}";
                }
                
                $paramStrings[] = $paramStr;
            }
            
            $code .= implode(', ', $paramStrings) . ')';
            
            if ($config['return_type']) {
                $code .= ": {$config['return_type']}";
            }
            
            $code .= "\n    {\n";
            $code .= "        " . str_replace("\n", "\n        ", trim($config['body'])) . "\n";
            $code .= "    }\n\n";
        }
        
        $code .= "}\n";
        
        return $code;
    }
    
    public function createClass(): string {
        $code = $this->generateCode();
        
        // Evaluate the code to create the class
        eval(str_replace('<?php', '', $code));
        
        $fullClassName = empty($this->namespace) ? $this->className : $this->namespace . '\\' . $this->className;
        
        return $fullClassName;
    }
    
    public function saveToFile(string $filename): void {
        $code = $this->generateCode();
        file_put_contents($filename, $code);
    }
}

// Example: Create a dynamic model class
$builder = new DynamicClassBuilder('User')
    ->setNamespace('App\\Models')
    ->setDocComment('/**
 * Dynamically generated User model
 * @author Dynamic Class Builder
 */')
    ->addProperty('id', 'private', 'int')
    ->addProperty('name', 'private', 'string')
    ->addProperty('email', 'private', 'string')
    ->addProperty('createdAt', 'private', 'DateTime')
    ->addConstant('TABLE_NAME', 'users')
    ->addMethod('__construct', 
        'id = $id;
        $this->name = $name;
        $this->email = $email;
        $this->createdAt = new DateTime();', 
        'public', 
        null, 
        [
            ['name' => 'id', 'type' => 'int'],
            ['name' => 'name', 'type' => 'string'],
            ['name' => 'email', 'type' => 'string']
        ]
    )
    ->addMethod('getId', 'return $this->id;', 'public', 'int')
    ->addMethod('getName', 'return $this->name;', 'public', 'string')
    ->addMethod('getEmail', 'return $this->email;', 'public', 'string')
    ->addMethod('setName', '$this->name = $name;', 'public', 'void', [['name' => 'name', 'type' => 'string']])
    ->addMethod('setEmail', '$this->email = $email;', 'public', 'void', [['name' => 'email', 'type' => 'string']])
    ->addMethod('toArray', 
        'return [
            "id" => $this->id,
            "name" => $this->name,
            "email" => $this->email,
            "created_at" => $this->createdAt->format("Y-m-d H:i:s")
        ];', 
        'public', 
        'array'
    );

// Generate and save the class
echo $builder->generateCode();
?>

Dynamic Interface and Trait Generation

<?php
class InterfaceGenerator {
    private string $interfaceName;
    private string $namespace = '';
    private array $extends = [];
    private array $methods = [];
    private string $docComment = '';
    
    public function __construct(string $interfaceName) {
        $this->interfaceName = $interfaceName;
    }
    
    public function setNamespace(string $namespace): self {
        $this->namespace = $namespace;
        return $this;
    }
    
    public function extends(string ...$interfaces): self {
        $this->extends = array_merge($this->extends, $interfaces);
        return $this;
    }
    
    public function addMethod(string $name, ?string $returnType = null, array $parameters = []): self {
        $this->methods[$name] = [
            'return_type' => $returnType,
            'parameters' => $parameters
        ];
        return $this;
    }
    
    public function setDocComment(string $docComment): self {
        $this->docComment = $docComment;
        return $this;
    }
    
    public function generateCode(): string {
        $code = "<?php\n\n";
        
        // Namespace
        if (!empty($this->namespace)) {
            $code .= "namespace {$this->namespace};\n\n";
        }
        
        // Interface declaration
        if (!empty($this->docComment)) {
            $code .= $this->docComment . "\n";
        }
        
        $code .= "interface {$this->interfaceName}";
        
        if (!empty($this->extends)) {
            $code .= " extends " . implode(', ', $this->extends);
        }
        
        $code .= "\n{\n";
        
        // Methods
        foreach ($this->methods as $name => $config) {
            $code .= "    public function {$name}(";
            
            // Parameters
            $paramStrings = [];
            foreach ($config['parameters'] as $param) {
                $paramStr = '';
                
                if (isset($param['type'])) {
                    $paramStr .= $param['type'] . ' ';
                }
                
                $paramStr .= '$' . $param['name'];
                
                $paramStrings[] = $paramStr;
            }
            
            $code .= implode(', ', $paramStrings) . ')';
            
            if ($config['return_type']) {
                $code .= ": {$config['return_type']}";
            }
            
            $code .= ";\n";
        }
        
        $code .= "}\n";
        
        return $code;
    }
}

class TraitGenerator {
    private string $traitName;
    private string $namespace = '';
    private array $properties = [];
    private array $methods = [];
    private string $docComment = '';
    
    public function __construct(string $traitName) {
        $this->traitName = $traitName;
    }
    
    public function setNamespace(string $namespace): self {
        $this->namespace = $namespace;
        return $this;
    }
    
    public function addProperty(string $name, string $visibility = 'private', ?string $type = null, mixed $defaultValue = null): self {
        $this->properties[$name] = [
            'visibility' => $visibility,
            'type' => $type,
            'default' => $defaultValue
        ];
        return $this;
    }
    
    public function addMethod(string $name, string $body, string $visibility = 'public', ?string $returnType = null, array $parameters = []): self {
        $this->methods[$name] = [
            'visibility' => $visibility,
            'return_type' => $returnType,
            'parameters' => $parameters,
            'body' => $body
        ];
        return $this;
    }
    
    public function generateCode(): string {
        $code = "<?php\n\n";
        
        // Namespace
        if (!empty($this->namespace)) {
            $code .= "namespace {$this->namespace};\n\n";
        }
        
        // Trait declaration
        if (!empty($this->docComment)) {
            $code .= $this->docComment . "\n";
        }
        
        $code .= "trait {$this->traitName}\n{\n";
        
        // Properties
        foreach ($this->properties as $name => $config) {
            $code .= "    {$config['visibility']}";
            
            if ($config['type']) {
                $code .= " {$config['type']}";
            }
            
            $code .= " \${$name}";
            
            if ($config['default'] !== null) {
                $defaultStr = is_string($config['default']) ? "'{$config['default']}'" : var_export($config['default'], true);
                $code .= " = {$defaultStr}";
            }
            
            $code .= ";\n";
        }
        
        if (!empty($this->properties)) {
            $code .= "\n";
        }
        
        // Methods
        foreach ($this->methods as $name => $config) {
            $code .= "    {$config['visibility']} function {$name}(";
            
            // Parameters
            $paramStrings = [];
            foreach ($config['parameters'] as $param) {
                $paramStr = '';
                
                if (isset($param['type'])) {
                    $paramStr .= $param['type'] . ' ';
                }
                
                $paramStr .= '$' . $param['name'];
                
                if (isset($param['default'])) {
                    $defaultStr = is_string($param['default']) ? "'{$param['default']}'" : var_export($param['default'], true);
                    $paramStr .= " = {$defaultStr}";
                }
                
                $paramStrings[] = $paramStr;
            }
            
            $code .= implode(', ', $paramStrings) . ')';
            
            if ($config['return_type']) {
                $code .= ": {$config['return_type']}";
            }
            
            $code .= "\n    {\n";
            $code .= "        " . str_replace("\n", "\n        ", trim($config['body'])) . "\n";
            $code .= "    }\n\n";
        }
        
        $code .= "}\n";
        
        return $code;
    }
}
?>

Advanced Reflection Patterns

Annotation/Attribute System

<?php
// PHP 8+ Attribute-based system
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY)]
class Route {
    public function __construct(
        public string $path,
        public array $methods = ['GET'],
        public string $name = '',
        public array $middleware = []
    ) {}
}

#[Attribute(Attribute::TARGET_PROPERTY)]
class Validate {
    public function __construct(
        public array $rules = [],
        public ?string $message = null
    ) {}
}

#[Attribute(Attribute::TARGET_METHOD)]
class Cache {
    public function __construct(
        public int $ttl = 3600,
        public ?string $key = null
    ) {}
}

class AttributeProcessor {
    public static function processRoutes(object $controller): array {
        $reflection = new ReflectionClass($controller);
        $routes = [];
        
        // Process class-level routes
        $classAttributes = $reflection->getAttributes(Route::class);
        $classRoute = null;
        
        if (!empty($classAttributes)) {
            $classRoute = $classAttributes[0]->newInstance();
        }
        
        // Process method-level routes
        foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
            $methodAttributes = $method->getAttributes(Route::class);
            
            if (!empty($methodAttributes)) {
                $routeAttribute = $methodAttributes[0]->newInstance();
                
                // Combine class and method paths
                $fullPath = ($classRoute ? rtrim($classRoute->path, '/') : '') . '/' . ltrim($routeAttribute->path, '/');
                
                $routes[] = [
                    'path' => $fullPath,
                    'methods' => $routeAttribute->methods,
                    'handler' => [$controller, $method->getName()],
                    'name' => $routeAttribute->name ?: $method->getName(),
                    'middleware' => array_merge(
                        $classRoute ? $classRoute->middleware : [],
                        $routeAttribute->middleware
                    )
                ];
            }
        }
        
        return $routes;
    }
    
    public static function processValidation(object $object): array {
        $reflection = new ReflectionClass($object);
        $validationRules = [];
        
        foreach ($reflection->getProperties() as $property) {
            $attributes = $property->getAttributes(Validate::class);
            
            if (!empty($attributes)) {
                $validateAttribute = $attributes[0]->newInstance();
                $validationRules[$property->getName()] = [
                    'rules' => $validateAttribute->rules,
                    'message' => $validateAttribute->message
                ];
            }
        }
        
        return $validationRules;
    }
    
    public static function processCaching(object $object, string $methodName): ?array {
        $reflection = new ReflectionClass($object);
        
        if (!$reflection->hasMethod($methodName)) {
            return null;
        }
        
        $method = $reflection->getMethod($methodName);
        $attributes = $method->getAttributes(Cache::class);
        
        if (empty($attributes)) {
            return null;
        }
        
        $cacheAttribute = $attributes[0]->newInstance();
        
        return [
            'ttl' => $cacheAttribute->ttl,
            'key' => $cacheAttribute->key ?: $reflection->getName() . '::' . $methodName
        ];
    }
}

// Example usage
#[Route('/api/users', middleware: ['auth'])]
class UserController {
    #[Route('/profile', ['GET'], 'user.profile')]
    #[Cache(ttl: 1800)]
    public function getProfile(int $userId): array {
        return ['id' => $userId, 'name' => 'John Doe'];
    }
    
    #[Route('/{id}', ['GET'], 'user.show')]
    public function show(int $id): array {
        return ['id' => $id];
    }
    
    #[Route('', ['POST'], 'user.create')]
    public function create(array $data): array {
        return ['created' => true];
    }
}

class User {
    #[Validate(rules: ['required', 'string', 'max:255'])]
    public string $name;
    
    #[Validate(rules: ['required', 'email', 'unique:users'])]
    public string $email;
    
    #[Validate(rules: ['required', 'min:8'])]
    public string $password;
}

$controller = new UserController();
$routes = AttributeProcessor::processRoutes($controller);
print_r($routes);

$user = new User();
$validationRules = AttributeProcessor::processValidation($user);
print_r($validationRules);

$cacheInfo = AttributeProcessor::processCaching($controller, 'getProfile');
print_r($cacheInfo);
?>

Dependency Injection Container

<?php
class DependencyContainer {
    private array $bindings = [];
    private array $instances = [];
    private array $singletons = [];
    
    public function bind(string $abstract, $concrete = null, bool $singleton = false): void {
        if ($concrete === null) {
            $concrete = $abstract;
        }
        
        $this->bindings[$abstract] = [
            'concrete' => $concrete,
            'singleton' => $singleton
        ];
    }
    
    public function singleton(string $abstract, $concrete = null): void {
        $this->bind($abstract, $concrete, true);
    }
    
    public function instance(string $abstract, object $instance): void {
        $this->instances[$abstract] = $instance;
    }
    
    public function resolve(string $abstract): mixed {
        // Check if we have a cached instance
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
        
        // Check if we have a binding
        if (!isset($this->bindings[$abstract])) {
            // Try to auto-resolve if it's a class
            if (class_exists($abstract)) {
                return $this->build($abstract);
            }
            
            throw new InvalidArgumentException("No binding found for {$abstract}");
        }
        
        $binding = $this->bindings[$abstract];
        $concrete = $binding['concrete'];
        
        // Resolve the concrete
        if ($concrete instanceof Closure) {
            $object = $concrete($this);
        } elseif (is_string($concrete)) {
            $object = $this->build($concrete);
        } else {
            $object = $concrete;
        }
        
        // Cache singleton instances
        if ($binding['singleton']) {
            $this->instances[$abstract] = $object;
        }
        
        return $object;
    }
    
    private function build(string $concrete): object {
        $reflection = new ReflectionClass($concrete);
        
        if (!$reflection->isInstantiable()) {
            throw new InvalidArgumentException("Class {$concrete} is not instantiable");
        }
        
        $constructor = $reflection->getConstructor();
        
        if ($constructor === null) {
            return new $concrete();
        }
        
        $parameters = $constructor->getParameters();
        $dependencies = $this->resolveDependencies($parameters);
        
        return $reflection->newInstanceArgs($dependencies);
    }
    
    private function resolveDependencies(array $parameters): array {
        $dependencies = [];
        
        foreach ($parameters as $parameter) {
            $type = $parameter->getType();
            
            if ($type === null) {
                // No type hint, check for default value
                if ($parameter->isDefaultValueAvailable()) {
                    $dependencies[] = $parameter->getDefaultValue();
                } else {
                    throw new InvalidArgumentException(
                        "Cannot resolve parameter {$parameter->getName()} without type hint"
                    );
                }
            } elseif ($type instanceof ReflectionNamedType && !$type->isBuiltin()) {
                // Class dependency
                $dependencies[] = $this->resolve($type->getName());
            } else {
                // Built-in type, check for default value
                if ($parameter->isDefaultValueAvailable()) {
                    $dependencies[] = $parameter->getDefaultValue();
                } else {
                    throw new InvalidArgumentException(
                        "Cannot resolve built-in type {$type->getName()} for parameter {$parameter->getName()}"
                    );
                }
            }
        }
        
        return $dependencies;
    }
    
    public function call(callable $callback, array $parameters = []): mixed {
        if (is_array($callback)) {
            [$object, $method] = $callback;
            $reflection = new ReflectionMethod($object, $method);
        } elseif ($callback instanceof Closure) {
            $reflection = new ReflectionFunction($callback);
        } else {
            throw new InvalidArgumentException('Invalid callback provided');
        }
        
        $methodParameters = $reflection->getParameters();
        $dependencies = $this->resolveMethodDependencies($methodParameters, $parameters);
        
        return $reflection->invokeArgs(is_array($callback) ? $object : null, $dependencies);
    }
    
    private function resolveMethodDependencies(array $parameters, array $provided = []): array {
        $dependencies = [];
        
        foreach ($parameters as $parameter) {
            $name = $parameter->getName();
            
            // Check if parameter was provided
            if (array_key_exists($name, $provided)) {
                $dependencies[] = $provided[$name];
                continue;
            }
            
            $type = $parameter->getType();
            
            if ($type === null) {
                if ($parameter->isDefaultValueAvailable()) {
                    $dependencies[] = $parameter->getDefaultValue();
                } else {
                    throw new InvalidArgumentException(
                        "Cannot resolve parameter {$name} without type hint"
                    );
                }
            } elseif ($type instanceof ReflectionNamedType && !$type->isBuiltin()) {
                $dependencies[] = $this->resolve($type->getName());
            } else {
                if ($parameter->isDefaultValueAvailable()) {
                    $dependencies[] = $parameter->getDefaultValue();
                } else {
                    throw new InvalidArgumentException(
                        "Cannot resolve built-in type {$type->getName()} for parameter {$name}"
                    );
                }
            }
        }
        
        return $dependencies;
    }
    
    public function has(string $abstract): bool {
        return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]);
    }
    
    public function forget(string $abstract): void {
        unset($this->bindings[$abstract], $this->instances[$abstract]);
    }
    
    public function getBindings(): array {
        return $this->bindings;
    }
}

// Example usage
interface LoggerInterface {
    public function log(string $message): void;
}

class FileLogger implements LoggerInterface {
    public function __construct(private string $logFile = 'app.log') {}
    
    public function log(string $message): void {
        file_put_contents($this->logFile, date('Y-m-d H:i:s') . " - {$message}\n", FILE_APPEND);
    }
}

class DatabaseLogger implements LoggerInterface {
    public function log(string $message): void {
        // Log to database
        echo "Logging to database: {$message}\n";
    }
}

class UserService {
    public function __construct(
        private LoggerInterface $logger,
        private string $apiKey = 'default-key'
    ) {}
    
    public function createUser(string $name, string $email): array {
        $this->logger->log("Creating user: {$name} ({$email})");
        
        return [
            'id' => rand(1, 1000),
            'name' => $name,
            'email' => $email,
            'created_at' => date('Y-m-d H:i:s')
        ];
    }
}

class UserController {
    public function __construct(private UserService $userService) {}
    
    public function store(string $name, string $email): array {
        return $this->userService->createUser($name, $email);
    }
}

// Set up container
$container = new DependencyContainer();

// Bind interfaces to implementations
$container->bind(LoggerInterface::class, FileLogger::class);

// Bind with custom parameters
$container->bind(UserService::class, function($container) {
    return new UserService(
        $container->resolve(LoggerInterface::class),
        'custom-api-key'
    );
});

// Resolve and use
$controller = $container->resolve(UserController::class);
$result = $container->call([$controller, 'store'], [
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

print_r($result);
?>

Performance Considerations and Optimization

Reflection Performance Analysis

<?php
class ReflectionPerformanceAnalyzer {
    private array $timings = [];
    private array $memoryUsage = [];
    
    public function benchmarkReflectionOperations(string $className, int $iterations = 1000): array {
        $results = [];
        
        // Test class instantiation
        $results['class_instantiation'] = $this->benchmarkOperation(
            'Class Instantiation',
            function() use ($className) {
                new ReflectionClass($className);
            },
            $iterations
        );
        
        // Test method reflection
        $reflection = new ReflectionClass($className);
        $results['method_reflection'] = $this->benchmarkOperation(
            'Method Reflection',
            function() use ($reflection) {
                $reflection->getMethods();
            },
            $iterations
        );
        
        // Test property reflection
        $results['property_reflection'] = $this->benchmarkOperation(
            'Property Reflection',
            function() use ($reflection) {
                $reflection->getProperties();
            },
            $iterations
        );
        
        // Test method invocation
        if ($reflection->hasMethod('__construct')) {
            $object = $reflection->newInstance();
            $method = $reflection->getMethod('__construct');
            
            $results['method_invocation'] = $this->benchmarkOperation(
                'Method Invocation',
                function() use ($method, $object) {
                    $method->invoke($object);
                },
                $iterations
            );
        }
        
        return $results;
    }
    
    private function benchmarkOperation(string $name, callable $operation, int $iterations): array {
        $startTime = microtime(true);
        $startMemory = memory_get_usage(true);
        
        for ($i = 0; $i < $iterations; $i++) {
            $operation();
        }
        
        $endTime = microtime(true);
        $endMemory = memory_get_usage(true);
        
        $totalTime = $endTime - $startTime;
        $memoryUsed = $endMemory - $startMemory;
        
        return [
            'name' => $name,
            'iterations' => $iterations,
            'total_time' => $totalTime,
            'avg_time_per_operation' => $totalTime / $iterations,
            'operations_per_second' => $iterations / $totalTime,
            'memory_used' => $memoryUsed,
            'memory_per_operation' => $memoryUsed / $iterations
        ];
    }
    
    public function compareReflectionVsDirectAccess(object $object, string $methodName, int $iterations = 10000): array {
        $reflection = new ReflectionClass($object);
        $method = $reflection->getMethod($methodName);
        
        // Direct method call
        $directResult = $this->benchmarkOperation(
            'Direct Method Call',
            function() use ($object, $methodName) {
                $object->$methodName();
            },
            $iterations
        );
        
        // Reflection method call
        $reflectionResult = $this->benchmarkOperation(
            'Reflection Method Call',
            function() use ($method, $object) {
                $method->invoke($object);
            },
            $iterations
        );
        
        return [
            'direct' => $directResult,
            'reflection' => $reflectionResult,
            'overhead_factor' => $reflectionResult['avg_time_per_operation'] / $directResult['avg_time_per_operation']
        ];
    }
    
    public function analyzeReflectionCaching(string $className, int $iterations = 1000): array {
        // Without caching
        $withoutCacheResult = $this->benchmarkOperation(
            'Without Caching',
            function() use ($className) {
                $reflection = new ReflectionClass($className);
                $reflection->getMethods();
                $reflection->getProperties();
            },
            $iterations
        );
        
        // With caching
        $cachedReflection = new ReflectionClass($className);
        $withCacheResult = $this->benchmarkOperation(
            'With Caching',
            function() use ($cachedReflection) {
                $cachedReflection->getMethods();
                $cachedReflection->getProperties();
            },
            $iterations
        );
        
        return [
            'without_cache' => $withoutCacheResult,
            'with_cache' => $withCacheResult,
            'improvement_factor' => $withoutCacheResult['avg_time_per_operation'] / $withCacheResult['avg_time_per_operation']
        ];
    }
    
    public function generatePerformanceReport(array $results): string {
        $report = "=== REFLECTION PERFORMANCE ANALYSIS ===\n\n";
        
        foreach ($results as $testName => $result) {
            if (isset($result['name'])) {
                // Single operation result
                $report .= "Operation: {$result['name']}\n";
                $report .= "  Iterations: {$result['iterations']}\n";
                $report .= "  Total Time: " . number_format($result['total_time'], 6) . "s\n";
                $report .= "  Avg Time: " . number_format($result['avg_time_per_operation'] * 1000000, 2) . "μs\n";
                $report .= "  Ops/sec: " . number_format($result['operations_per_second'], 0) . "\n";
                $report .= "  Memory: " . $this->formatBytes($result['memory_used']) . "\n\n";
            } else {
                // Comparison result
                $report .= "Test: $testName\n";
                foreach ($result as $key => $data) {
                    if (is_array($data) && isset($data['name'])) {
                        $report .= "  {$data['name']}: " . number_format($data['avg_time_per_operation'] * 1000000, 2) . "μs\n";
                    } elseif ($key === 'overhead_factor') {
                        $report .= "  Overhead Factor: " . number_format($data, 2) . "x\n";
                    } elseif ($key === 'improvement_factor') {
                        $report .= "  Improvement Factor: " . number_format($data, 2) . "x\n";
                    }
                }
                $report .= "\n";
            }
        }
        
        return $report;
    }
    
    private function formatBytes(int $bytes): string {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = abs($bytes);
        
        for ($i = 0; $bytes >= 1024 && $i < count($units) - 1; $i++) {
            $bytes /= 1024;
        }
        
        return round($bytes, 2) . ' ' . $units[$i];
    }
}

// Example usage
class TestClass {
    private string $property = 'test';
    
    public function testMethod(): string {
        return 'test result';
    }
    
    public function complexMethod(string $param1, int $param2 = 42): array {
        return ['param1' => $param1, 'param2' => $param2];
    }
}

$analyzer = new ReflectionPerformanceAnalyzer();

// Benchmark basic reflection operations
$basicResults = $analyzer->benchmarkReflectionOperations(TestClass::class, 5000);

// Compare direct vs reflection method calls
$object = new TestClass();
$comparisonResults = $analyzer->compareReflectionVsDirectAccess($object, 'testMethod', 10000);

// Analyze caching benefits
$cachingResults = $analyzer->analyzeReflectionCaching(TestClass::class, 1000);

// Generate report
$allResults = [
    'basic_operations' => $basicResults,
    'direct_vs_reflection' => $comparisonResults,
    'caching_analysis' => $cachingResults
];

echo $analyzer->generatePerformanceReport($allResults);
?>

Frequently Asked Questions (FAQ)

When should I use Reflection instead of direct method calls?

Use Reflection when you need dynamic behavior that can't be determined at compile time, such as:

  • Building frameworks or libraries that work with unknown classes
  • Creating dependency injection containers
  • Implementing serialization/deserialization logic
  • Building ORM systems that map database rows to objects
  • Creating debugging and profiling tools

Avoid Reflection for regular application logic where the class structure is known at development time, as it's significantly slower than direct calls.

How can I improve Reflection performance in production applications?

Several strategies can improve Reflection performance:

  • Cache ReflectionClass instances: Create them once and reuse
  • Use opcache: PHP's opcache can help with Reflection operations
  • Lazy loading: Only perform reflection when absolutely necessary
  • Compile-time generation: Generate code at build time instead of using runtime reflection
  • Minimize reflection depth: Avoid deep introspection when possible

Is it safe to use Reflection to access private properties and methods?

While technically possible, accessing private members breaks encapsulation and can lead to maintenance issues. Use this capability sparingly and only for:

  • Testing frameworks that need to verify internal state
  • Debugging and development tools
  • Framework code that requires deep object inspection
  • Migration scripts that need to access legacy code

Always document when and why you're breaking encapsulation.

Can Reflection work with PHP 8 attributes effectively?

Yes, PHP 8's Reflection API has excellent support for attributes. You can:

  • Use getAttributes() to retrieve attribute instances
  • Filter attributes by type with getAttributes(AttributeClass::class)
  • Access attribute arguments and instantiate attribute objects
  • Build powerful metadata-driven systems similar to Java annotations or C# attributes

The attribute system is much more powerful and type-safe compared to parsing docblock comments.

Conclusion

PHP's Reflection API is a powerful tool that enables sophisticated metaprogramming patterns, from simple class inspection to complex framework development. While it comes with performance overhead, the flexibility it provides makes it indispensable for building dynamic, adaptable applications.

Key takeaways for effective Reflection usage:

  • Use judiciously: Reserve Reflection for scenarios requiring true dynamic behavior
  • Cache when possible: Reuse ReflectionClass instances to minimize overhead
  • Combine with modern features: Leverage PHP 8 attributes for type-safe metadata
  • Consider alternatives: Sometimes design patterns can achieve similar results with better performance

The examples and patterns shown in this guide provide a solid foundation for incorporating Reflection into your PHP projects. Start with simple introspection tasks and gradually build more complex dynamic systems as your understanding grows.

Ready to add dynamic capabilities to your PHP applications? Begin experimenting with the ClassAnalyzer and work your way up to building your own dependency injection container. Share your Reflection-powered creations and use cases in the comments below!

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Php