> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP Reflection API

> Funktionsweise der PHP Reflection API sowie ihr Einsatz im Laravel IoC-Container und in der Paketentwicklung.

## Was ist die PHP Reflection API?

Die PHP Reflection API ist eine eingebaute PHP-Funktionalität, um Metainformationen zu Klassen, Methoden, Properties, Funktionen und Parametern zur Laufzeit auszulesen und zu untersuchen. Sie können etwa herausfinden, welche Argumente ein Konstruktor erwartet oder welche Attribute an einer Methode hängen — ohne den Quellcode zu ändern.

Laravel nutzt die Reflection API intern in `Illuminate/Container/Container.php` intensiv, um automatische Auflösung im DI-Container, das Auslesen von PHP-Attributen und Method-Injection zu realisieren.

## Wichtige Klassen

| Klasse                | Wichtigster Einsatz                                                    |
| --------------------- | ---------------------------------------------------------------------- |
| `ReflectionClass`     | Einstiegspunkt für Metainformationen einer Klasse                      |
| `ReflectionMethod`    | Argumente, Zugriffsmodifikatoren und Attribute einer Methode           |
| `ReflectionProperty`  | Typen, Standardwerte und Attribute einer Property                      |
| `ReflectionParameter` | Argumentinformationen (Type-Hint, Standardwert) einer Methode/Funktion |
| `ReflectionFunction`  | Metainformationen einer Funktion/Closure                               |
| `ReflectionAttribute` | Klassenname und Argumente eines Attributs                              |

### ReflectionClass — Klasseninformationen ermitteln

```php theme={null}
$ref = new ReflectionClass(UserController::class);

$ref->getName();          // Voll qualifizierter Klassenname
$ref->getShortName();     // Nur Klassenname
$ref->isInstantiable();   // Ist die Klasse instanziierbar?
$ref->getConstructor();   // Konstruktor als ReflectionMethod
$ref->getMethods();       // Alle Methoden als ReflectionMethod[]
$ref->getProperties();    // Alle Properties als ReflectionProperty[]
$ref->getAttributes();    // Attribute der Klasse als ReflectionAttribute[]
```

### ReflectionParameter — Konstruktor-Argumente untersuchen

```php theme={null}
$ref = new ReflectionClass(UserController::class);
$constructor = $ref->getConstructor();

if ($constructor) {
    foreach ($constructor->getParameters() as $param) {
        $param->getName();           // Argumentname
        $param->getType();           // Type-Hint (ReflectionType)
        $param->isOptional();        // Ist das Argument optional?
        $param->isVariadic();        // Variadic?
        $param->getDefaultValue();   // Standardwert (falls vorhanden)
    }
}
```

## Der Laravel-Container und die Reflection API

Der IoC-Container von Laravel implementiert Konstruktor-Injection (automatische Auflösung von Abhängigkeiten) über die Reflection API. So funktioniert `app()->make(SomeClass::class)` und die Dependency Injection.

```mermaid theme={null}
sequenceDiagram
    participant App as App-Code
    participant Container as IoC-Container
    participant Reflection as ReflectionClass
    participant Dep as Abhängige Klasse

    App->>Container: app()->make(UserController::class)
    Container->>Reflection: new ReflectionClass(UserController::class)
    Reflection-->>Container: Konstruktor-Info
    Container->>Reflection: getConstructor()->getParameters()
    Reflection-->>Container: [UserRepository, Cache, ...]
    loop Für jedes Argument auflösen
        Container->>Container: Rekursiv make() über Type-Hint
        Container->>Dep: new Dep(...)
        Dep-->>Container: Instanz
    end
    Container-->>App: new UserController(repository, cache, ...)
```

### Die `build()`-Methode des Containers (vereinfacht)

Die tatsächliche `build()`-Methode in `Container.php` sieht in etwa so aus:

```php theme={null}
// Vereinfachte Illuminate\Container\Container::build()
public function build($concrete)
{
    // 1. Klasse mit ReflectionClass inspizieren
    $reflector = new ReflectionClass($concrete);

    // Nicht instanziierbare Klassen (Interface, Abstract usw.) → Fehler
    if (! $reflector->isInstantiable()) {
        throw new BindingResolutionException("[$concrete] is not instantiable.");
    }

    // 2. Konstruktor ermitteln
    $constructor = $reflector->getConstructor();

    // Kein Konstruktor → direkt instanziieren
    if (is_null($constructor)) {
        return new $concrete;
    }

    // 3. Alle Konstruktorparameter ermitteln
    $dependencies = $constructor->getParameters();

    // 4. Jedes Argument rekursiv auflösen
    $instances = $this->resolveDependencies($dependencies);

    return new $concrete(...$instances);
}

protected function resolveDependencies(array $dependencies): array
{
    $results = [];

    foreach ($dependencies as $dependency) {
        // Bei vorhandenem Type-Hint rekursiv über Container auflösen
        $className = Util::getParameterClassName($dependency);

        $results[] = is_null($className)
            ? $this->resolvePrimitive($dependency)  // Primitivtyp
            : $this->resolveClass($dependency, $className); // Klassentyp
    }

    return $results;
}
```

<Info>
  `Util::getParameterClassName()` extrahiert den Typnamen aus dem Ergebnis von `$parameter->getType()`. Es umhüllt den von `ReflectionParameter::getType()` gelieferten `ReflectionNamedType` bequemer.
</Info>

## PHP-Attribute auslesen

Ab PHP 8.0 lassen sich Attribute an Klassen, Methoden und Properties über die Reflection API auslesen. Laravel verarbeitet damit Queue- und Eloquent-Attribute.

<Tip>
  Für den Einsatz von PHP-Attributen in Laravel siehe auch [PHP-Attribute](/de/advanced/php-attributes).
</Tip>

### Grundmuster zum Auslesen von Attributen

```php theme={null}
use ReflectionClass;

// 1. Attribute einer Klasse holen
$ref = new ReflectionClass(ProcessOrder::class);
$attrs = $ref->getAttributes(Queue::class); // Nur bestimmte Attribute holen

foreach ($attrs as $attr) {
    $instance = $attr->newInstance(); // Attributklasse instanziieren
    echo $instance->queue;            // Property des Attributs lesen
}

// 2. Alle Attribute holen (ohne Filter)
$allAttrs = $ref->getAttributes();

foreach ($allAttrs as $attr) {
    echo $attr->getName();       // Attributklassenname (FQCN)
    print_r($attr->getArguments()); // Konstruktor-Argumente
}
```

### Wie Laravel Queue-Attribute liest (vereinfacht)

```php theme={null}
// Vereinfachtes ReadsQueueAttributes aus InteractsWithQueue
protected function setJobInstanceForQueue(object $job): void
{
    $reflection = new ReflectionClass($job);

    foreach ($reflection->getAttributes(Queue::class) as $attribute) {
        $instance = $attribute->newInstance();
        $job->queue = $instance->queue instanceof \UnitEnum
            ? $instance->queue->value
            : $instance->queue;
    }
}
```

### Method-Attribute auslesen

```php theme={null}
$ref = new ReflectionClass(UserController::class);

foreach ($ref->getMethods() as $method) {
    $attrs = $method->getAttributes(Route::class);

    foreach ($attrs as $attr) {
        $route = $attr->newInstance();
        echo "{$method->getName()} => {$route->path}";
    }
}
```

## Anwendungsbeispiele in der Paketentwicklung

### Prüfen, welche Interfaces eine Klasse implementiert

In einem Paket können Sie dynamisch feststellen, ob eine Klasse ein bestimmtes Interface implementiert.

```php theme={null}
use ReflectionClass;

function isQueueable(string $class): bool
{
    $ref = new ReflectionClass($class);

    return $ref->implementsInterface(\Illuminate\Contracts\Queue\ShouldQueue::class);
}
```

### Metadaten sammeln — Routen automatisch per Attribut registrieren

Ein Muster, in dem Attribute und Reflection kombiniert werden, um Routen automatisch einzusammeln.

```php theme={null}
// Eigenes Route-Attribut
#[\Attribute(\Attribute::TARGET_METHOD)]
class Route
{
    public function __construct(
        public string $method,
        public string $path,
    ) {}
}

// Verwendung im Controller
class UserController
{
    #[Route('GET', '/users')]
    public function index() { /* ... */ }

    #[Route('POST', '/users')]
    public function store() { /* ... */ }
}

// Service Provider, der Routen automatisch aus Attributen registriert
class AttributeRouteServiceProvider extends ServiceProvider
{
    public function boot(Router $router): void
    {
        $ref = new ReflectionClass(UserController::class);

        foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
            foreach ($method->getAttributes(Route::class) as $attr) {
                $route = $attr->newInstance();
                $router->addRoute(
                    $route->method,
                    $route->path,
                    [UserController::class, $method->getName()],
                );
            }
        }
    }
}
```

### Dynamische Methodenaufrufe — Method-Injection

Laravels `call()`-Methode löst Argumente per Reflection auf. So lässt sich derselbe Mechanismus in einem Paket bauen.

```php theme={null}
use ReflectionFunction;
use ReflectionMethod;

function callWithDependencies(callable $callable, Container $container): mixed
{
    if (is_array($callable)) {
        [$object, $method] = $callable;
        $ref = new ReflectionMethod($object, $method);
        $params = $ref->getParameters();
    } else {
        $ref = new ReflectionFunction($callable);
        $params = $ref->getParameters();
    }

    $args = [];
    foreach ($params as $param) {
        $type = $param->getType()?->getName();
        $args[] = $type ? $container->make($type) : null;
    }

    return $callable(...$args);
}

// Anwendungsbeispiel
callWithDependencies([new UserController(), 'index'], app());
```

### Standardwerte von Properties einsammeln

Muster, um Defaults aus einer Config-Klasse per Reflection zu extrahieren.

```php theme={null}
use ReflectionClass;
use ReflectionProperty;

function getDefaults(string $class): array
{
    $ref = new ReflectionClass($class);
    $defaults = [];

    foreach ($ref->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) {
        if ($prop->hasDefaultValue()) {
            $defaults[$prop->getName()] = $prop->getDefaultValue();
        }
    }

    return $defaults;
}

class DatabaseConfig
{
    public string $driver = 'mysql';
    public int $port = 3306;
    public bool $strict = true;
}

// ['driver' => 'mysql', 'port' => 3306, 'strict' => true]
$defaults = getDefaults(DatabaseConfig::class);
```

## Performance-Überlegungen

Die Reflection API parst Klasseninformationen jedes Mal neu, was Kosten verursacht. In Produktionscode empfiehlt es sich, Ergebnisse zu cachen.

```php theme={null}
class ReflectionCache
{
    private static array $cache = [];

    public static function getClass(string $class): \ReflectionClass
    {
        return self::$cache[$class] ??= new \ReflectionClass($class);
    }
}

// Anwendungsbeispiel
$ref = ReflectionCache::getClass(UserController::class);
```

<Warning>
  PHP OPcache cacht keine Reflection-Ergebnisse. Wenn Sie viele Klassen in einer Schleife untersuchen, sollten Sie eigenes Caching einbauen. Der Laravel-Container selbst wiederverwendet innerhalb desselben Requests bereits `ReflectionClass`-Instanzen.
</Warning>

## Nächste Schritte

<Columns cols={2}>
  <Card title="PHP-Attribute" icon="tag" href="/de/advanced/php-attributes">
    Details zum Auslesen von PHP-Attributen mit ReflectionClass::getAttributes().
  </Card>

  <Card title="Paketentwicklung" icon="package" href="/de/advanced/package-development">
    Wie Sie Laravel-Pakete mithilfe der Reflection API entwickeln.
  </Card>
</Columns>


## Related topics

- [PHP-Attribute](/de/advanced/php-attributes.md)
- [API-Referenz - VOICEVOX Core für PHP](/de/packages/voicevox-core-php/api.md)
- [FAQ zur neuen App-Struktur ab Laravel 11](/de/advanced/app-structure-faq.md)
- [Service-Container](/de/service-container.md)
- [Google Sheets API for Laravel](/de/packages/laravel-google-sheets/index.md)
