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

# API PHP Reflection

> Découvrez le fonctionnement de l'API PHP Reflection et son utilisation dans le conteneur IoC de Laravel et dans le développement de packages.

## Qu'est-ce que l'API PHP Reflection

L'API PHP Reflection est une fonctionnalité intégrée à PHP permettant d'obtenir et d'inspecter à l'exécution les méta-informations des classes, méthodes, propriétés, fonctions ou paramètres. Vous pouvez ainsi vérifier les arguments du constructeur d'une classe, ou les attributs posés sur une méthode, sans modifier directement le code source.

Laravel utilise abondamment l'API Reflection à l'intérieur de `Illuminate/Container/Container.php` pour la résolution automatique du conteneur DI, la lecture des attributs PHP ou l'injection dans les méthodes.

## Classes principales

| Classe                | Usage principal                                                              |
| --------------------- | ---------------------------------------------------------------------------- |
| `ReflectionClass`     | Point d'entrée pour obtenir les méta-informations d'une classe               |
| `ReflectionMethod`    | Récupère les arguments, modificateurs et attributs d'une méthode             |
| `ReflectionProperty`  | Récupère le type, la valeur par défaut et les attributs d'une propriété      |
| `ReflectionParameter` | Récupère les informations sur un paramètre (hint de type, valeur par défaut) |
| `ReflectionFunction`  | Récupère les méta-informations d'une fonction ou closure                     |
| `ReflectionAttribute` | Récupère le nom de classe et les arguments d'un attribut                     |

### ReflectionClass — obtenir des informations sur une classe

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

$ref->getName();          // Nom complètement qualifié de la classe
$ref->getShortName();     // Nom court de la classe
$ref->isInstantiable();   // Peut-elle être instanciée ?
$ref->getConstructor();   // Retourne le constructeur en tant que ReflectionMethod
$ref->getMethods();       // Retourne toutes les méthodes en ReflectionMethod[]
$ref->getProperties();    // Retourne toutes les propriétés en ReflectionProperty[]
$ref->getAttributes();    // Retourne les attributs de la classe en ReflectionAttribute[]
```

### ReflectionParameter — inspecter les arguments d'un constructeur

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

if ($constructor) {
    foreach ($constructor->getParameters() as $param) {
        $param->getName();           // Nom de l'argument
        $param->getType();           // Hint de type (ReflectionType)
        $param->isOptional();        // Optionnel ?
        $param->isVariadic();        // Variadique ?
        $param->getDefaultValue();   // Valeur par défaut (si présente)
    }
}
```

## Conteneur Laravel et API Reflection

Le conteneur IoC de Laravel s'appuie sur l'API Reflection pour l'injection par constructeur (résolution automatique des dépendances). Comprenons le mécanisme derrière `app()->make(SomeClass::class)` et l'injection de dépendances.

```mermaid theme={null}
sequenceDiagram
    participant App as code de l'app
    participant Container as conteneur IoC
    participant Reflection as ReflectionClass
    participant Dep as classe dépendante

    App->>Container: app()->make(UserController::class)
    Container->>Reflection: new ReflectionClass(UserController::class)
    Reflection-->>Container: infos sur le constructeur
    Container->>Reflection: getConstructor()->getParameters()
    Reflection-->>Container: [UserRepository, Cache, ...]
    loop résolution de chaque paramètre
        Container->>Container: make() récursif via le hint de type
        Container->>Dep: new Dep(...)
        Dep-->>Container: instance
    end
    Container-->>App: new UserController(repository, cache, ...)
```

### La méthode `build()` du conteneur (version simplifiée)

Le vrai `build()` de `Container.php` ressemble à peu près à ceci.

```php theme={null}
// Simplification de Illuminate\Container\Container::build()
public function build($concrete)
{
    // 1. Inspection de la classe via ReflectionClass
    $reflector = new ReflectionClass($concrete);

    // Les classes non instanciables (interface, abstract, etc.) provoquent une erreur
    if (! $reflector->isInstantiable()) {
        throw new BindingResolutionException("[$concrete] is not instantiable.");
    }

    // 2. Récupérer le constructeur
    $constructor = $reflector->getConstructor();

    // Pas de constructeur → instancier tel quel
    if (is_null($constructor)) {
        return new $concrete;
    }

    // 3. Récupérer tous les paramètres du constructeur
    $dependencies = $constructor->getParameters();

    // 4. Résoudre chaque paramètre de manière récursive
    $instances = $this->resolveDependencies($dependencies);

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

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

    foreach ($dependencies as $dependency) {
        // Si un hint de type est disponible, résolution récursive via le conteneur
        $className = Util::getParameterClassName($dependency);

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

    return $results;
}
```

<Info>
  `Util::getParameterClassName()` est un utilitaire qui extrait le nom du type sous forme de chaîne à partir du résultat de `$parameter->getType()`. Il enveloppe le `ReflectionNamedType` renvoyé par `ReflectionParameter::getType()` de manière plus commode.
</Info>

## Lire les attributs PHP

Depuis PHP 8.0, l'API Reflection permet de récupérer les attributs posés sur des classes, méthodes ou propriétés. Laravel s'en sert pour traiter les attributs de queue ou d'Eloquent.

<Tip>
  Pour l'intégration des attributs PHP dans Laravel, voir aussi [Attributs PHP](/fr/advanced/php-attributes).
</Tip>

### Schéma de base pour lire un attribut

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

// 1. Récupérer les attributs posés sur la classe
$ref = new ReflectionClass(ProcessOrder::class);
$attrs = $ref->getAttributes(Queue::class); // Ne récupère que l'attribut donné

foreach ($attrs as $attr) {
    $instance = $attr->newInstance(); // Instancie la classe d'attribut
    echo $instance->queue;            // Lit une propriété de l'attribut
}

// 2. Récupérer tous les attributs (sans filtre)
$allAttrs = $ref->getAttributes();

foreach ($allAttrs as $attr) {
    echo $attr->getName();       // Nom (FQCN) de la classe d'attribut
    print_r($attr->getArguments()); // Arguments du constructeur
}
```

### Comment Laravel lit l'attribut Queue (version simplifiée)

```php theme={null}
// Simplification de ReadsQueueAttributes dans le trait 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;
    }
}
```

### Lire les attributs d'une méthode

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

## Utilisations en développement de packages

### Vérifier les interfaces implémentées par une classe

Vous pouvez vérifier dynamiquement si une classe implémente une interface donnée depuis votre package.

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

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

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

### Récupération de métadonnées — enregistrer automatiquement des routes via attributs

Un schéma combinant attributs et Reflection pour collecter automatiquement les routes.

```php theme={null}
// Définition d'un attribut Route maison
#[\Attribute(\Attribute::TARGET_METHOD)]
class Route
{
    public function __construct(
        public string $method,
        public string $path,
    ) {}
}

// Utilisation dans un contrôleur
class UserController
{
    #[Route('GET', '/users')]
    public function index() { /* ... */ }

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

// Service provider qui enregistre les routes à partir des attributs
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()],
                );
            }
        }
    }
}
```

### Appel dynamique de méthode — injection de méthode

La méthode `call()` de Laravel utilise Reflection pour résoudre automatiquement les arguments. Voici comment implémenter le même mécanisme dans un package.

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

// Exemple d'utilisation
callWithDependencies([new UserController(), 'index'], app());
```

### Récupérer les valeurs par défaut des propriétés

Schéma pour récupérer les valeurs par défaut d'une classe de configuration via Reflection.

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

## Attention aux performances

L'API Reflection parse les informations de classe à chaque appel : cela a un coût. En production, la bonne pratique est de mettre les résultats en cache.

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

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

// Exemple d'utilisation
$ref = ReflectionCache::getClass(UserController::class);
```

<Warning>
  L'OPcache de PHP ne met pas en cache les résultats de Reflection. Si vous inspectez de nombreuses classes en boucle, envisagez un cache personnalisé. Notez toutefois que le conteneur Laravel réutilise déjà l'instance `ReflectionClass` dans la même requête.
</Warning>

## Étapes suivantes

<Columns cols={2}>
  <Card title="Attributs PHP" icon="tag" href="/fr/advanced/php-attributes">
    Découvrez en détail les attributs PHP lus via `ReflectionClass::getAttributes()`.
  </Card>

  <Card title="Développement de packages" icon="package" href="/fr/advanced/package-development">
    Découvrez comment développer un package Laravel en tirant parti de l'API Reflection.
  </Card>
</Columns>


## Related topics

- [Attributs PHP](/fr/advanced/php-attributes.md)
- [Référence API - VOICEVOX Core for PHP](/fr/packages/voicevox-core-php/api.md)
- [FAQ sur la nouvelle structure d'application Laravel 11+](/fr/advanced/app-structure-faq.md)
- [PHP FFI](/fr/advanced/ffi.md)
- [Google Sheets API for Laravel](/fr/packages/laravel-google-sheets/index.md)
