> ## 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

> Hoe de PHP Reflection API werkt en hoe je die inzet in de IoC-container van Laravel en bij packageontwikkeling.

## Wat is de PHP Reflection API?

De PHP Reflection API is een ingebouwde PHP-functionaliteit waarmee je tijdens runtime meta-informatie over klassen, methodes, properties, functies en parameters kunt ophalen en inspecteren. Je kunt bijvoorbeeld nagaan welke argumenten de constructor van een klasse verwacht of welke attributes op een methode staan, zonder de broncode zelf aan te passen.

Laravel gebruikt de Reflection API intensief binnen `Illuminate/Container/Container.php` en realiseert daarmee automatische resolutie in de DI-container, het uitlezen van PHP-attributes en method injection.

## De belangrijkste klassen

| Klasse                | Voornaamste gebruik                                                             |
| --------------------- | ------------------------------------------------------------------------------- |
| `ReflectionClass`     | Startpunt om meta-informatie van een klasse op te halen                         |
| `ReflectionMethod`    | Argumenten, access modifiers en attributes van een methode ophalen              |
| `ReflectionProperty`  | Type, standaardwaarde en attributes van een property ophalen                    |
| `ReflectionParameter` | Argumentinformatie van methodes/functies ophalen (type hints, standaardwaarden) |
| `ReflectionFunction`  | Meta-informatie van functies en closures ophalen                                |
| `ReflectionAttribute` | Klassenaam en argumenten van een attribute ophalen                              |

### ReflectionClass — klasse-informatie ophalen

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

$ref->getName();          // Volledig gekwalificeerde klassenaam
$ref->getShortName();     // Alleen de klassenaam
$ref->isInstantiable();   // Kan de klasse geïnstantieerd worden?
$ref->getConstructor();   // Geeft de constructor terug als ReflectionMethod
$ref->getMethods();       // Geeft alle methodes terug als ReflectionMethod[]
$ref->getProperties();    // Geeft alle properties terug als ReflectionProperty[]
$ref->getAttributes();    // Geeft de attributes op de klasse terug als ReflectionAttribute[]
```

### ReflectionParameter — constructorargumenten inspecteren

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

if ($constructor) {
    foreach ($constructor->getParameters() as $param) {
        $param->getName();           // Argumentnaam
        $param->getType();           // Type hint (ReflectionType)
        $param->isOptional();        // Is het argument optioneel?
        $param->isVariadic();        // Is het een variadisch argument?
        $param->getDefaultValue();   // Standaardwaarde (indien aanwezig)
    }
}
```

## De Laravel-container en de Reflection API

De IoC-container van Laravel realiseert constructorinjectie (automatische resolutie van dependencies) met behulp van de Reflection API. Laten we begrijpen hoe `app()->make(SomeClass::class)` en dependency injection werken.

```mermaid theme={null}
sequenceDiagram
    participant App as Applicatiecode
    participant Container as IoC-container
    participant Reflection as ReflectionClass
    participant Dep as Dependency-klasse

    App->>Container: app()->make(UserController::class)
    Container->>Reflection: new ReflectionClass(UserController::class)
    Reflection-->>Container: Constructorinformatie
    Container->>Reflection: getConstructor()->getParameters()
    Reflection-->>Container: [UserRepository, Cache, ...]
    loop Elk argument oplossen
        Container->>Container: Recursief make() via de type hint
        Container->>Dep: new Dep(...)
        Dep-->>Container: Instantie
    end
    Container-->>App: new UserController(repository, cache, ...)
```

### De `build()`-methode van de container (vereenvoudigd)

De echte `build()`-methode in `Container.php` ziet er ongeveer zo uit.

```php theme={null}
// Vereenvoudiging van Illuminate\Container\Container::build()
public function build($concrete)
{
    // 1. De klasse inspecteren met ReflectionClass
    $reflector = new ReflectionClass($concrete);

    // Klassen die niet te instantiëren zijn (interface, abstract, enz.) geven een fout
    if (! $reflector->isInstantiable()) {
        throw new BindingResolutionException("[$concrete] is not instantiable.");
    }

    // 2. De constructor ophalen
    $constructor = $reflector->getConstructor();

    // Geen constructor → direct instantiëren
    if (is_null($constructor)) {
        return new $concrete;
    }

    // 3. Alle parameters van de constructor ophalen
    $dependencies = $constructor->getParameters();

    // 4. Elke parameter recursief oplossen
    $instances = $this->resolveDependencies($dependencies);

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

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

    foreach ($dependencies as $dependency) {
        // Als er een type hint beschikbaar is, recursief oplossen via de container
        $className = Util::getParameterClassName($dependency);

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

    return $results;
}
```

<Info>
  `Util::getParameterClassName()` is een utility die de typenaam als string haalt uit het resultaat van `$parameter->getType()`. Het wrapt de `ReflectionNamedType` die `ReflectionParameter::getType()` teruggeeft in een handzamere vorm.
</Info>

## PHP-attributes uitlezen

Sinds PHP 8.0 kun je met de Reflection API de attributes ophalen die op klassen, methodes en properties staan. Laravel gebruikt dit mechanisme om queue-attributes en Eloquent-attributes te verwerken.

<Tip>
  Zie ook [PHP-attributes](/nl/advanced/php-attributes) voor PHP-attributes en hoe ze in Laravel zijn ingebouwd.
</Tip>

### Het basispatroon voor het uitlezen van attributes

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

// 1. De attributes op een klasse ophalen
$ref = new ReflectionClass(ProcessOrder::class);
$attrs = $ref->getAttributes(Queue::class); // Alleen een specifiek attribute ophalen

foreach ($attrs as $attr) {
    $instance = $attr->newInstance(); // De attribute-klasse instantiëren
    echo $instance->queue;            // De property van het attribute lezen
}

// 2. Alle attributes ophalen (zonder filter)
$allAttrs = $ref->getAttributes();

foreach ($allAttrs as $attr) {
    echo $attr->getName();       // Klassenaam van het attribute (FQCN)
    print_r($attr->getArguments()); // Constructorargumenten
}
```

### Hoe Laravel het Queue-attribute uitleest (vereenvoudigd)

```php theme={null}
// Vereenvoudigd uit ReadsQueueAttributes van de InteractsWithQueue-trait
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;
    }
}
```

### Attributes van methodes uitlezen

```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}";
    }
}
```

## Toepassingsvoorbeelden in packageontwikkeling

### Controleren welke interfaces een klasse implementeert

In een package kun je dynamisch controleren of een klasse een bepaalde interface implementeert.

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

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

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

### Metadata ophalen — routes automatisch registreren met attributes

Een patroon waarbij je attributes en Reflection combineert om routes automatisch te verzamelen.

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

// Gebruiken in een controller
class UserController
{
    #[Route('GET', '/users')]
    public function index() { /* ... */ }

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

// Een service provider die routes automatisch registreert op basis van attributes
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 methodeaanroepen — method injection

De `call()`-methode van Laravel lost argumenten automatisch op via Reflection. Een voorbeeld waarin je hetzelfde mechanisme in een package implementeert.

```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);
}

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

### Standaardwaarden van properties verzamelen

Een patroon waarmee je de standaardwaarden van een configuratieklasse via Reflection ophaalt.

```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);
```

## Aandacht voor performance

De Reflection API parset klasse-informatie elke keer opnieuw en heeft dus kosten. In productiecode is het cachen van de resultaten een best practice.

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

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

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

<Warning>
  De OPcache van PHP cachet Reflection-resultaten niet. Als je grote aantallen klassen in een lus inspecteert, overweeg dan een eigen cache. De Laravel-container zelf hergebruikt overigens binnen één request ook `ReflectionClass`-instanties.
</Warning>

## Volgende stappen

<Columns cols={2}>
  <Card title="PHP-attributes" icon="tag" href="/nl/advanced/php-attributes">
    Leer de details van PHP-attributes, die je uitleest met ReflectionClass::getAttributes().
  </Card>

  <Card title="Packageontwikkeling" icon="package" href="/nl/advanced/package-development">
    Leer hoe je Laravel-packages ontwikkelt met behulp van de Reflection API.
  </Card>
</Columns>


## Related topics

- [PHP-attributes](/nl/advanced/php-attributes.md)
- [API-referentie - VOICEVOX Core for PHP](/nl/packages/voicevox-core-php/api.md)
- [FAQ over de nieuwe appstructuur van Laravel 11+](/nl/advanced/app-structure-faq.md)
- [Nieuwe functies in Laravel 13](/nl/blog/laravel-13-new-features.md)
- [PHP FFI](/nl/advanced/ffi.md)
