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

> Il meccanismo della PHP Reflection API e come sfruttarla nell'IoC container di Laravel e nello sviluppo di pacchetti.

## Cos'è la PHP Reflection API

La PHP Reflection API è una funzionalità integrata di PHP che permette di ottenere e ispezionare a runtime le meta-informazioni di classi, metodi, proprietà, funzioni e parametri. Puoi scoprire quali argomenti riceve un costruttore o quali attributi sono applicati a un metodo, senza modificare il codice sorgente.

Laravel usa massicciamente la Reflection API dentro `Illuminate/Container/Container.php` per realizzare la risoluzione automatica del DI container, la lettura degli attributi PHP, la method injection e altro ancora.

## Classi principali

| Classe                | Uso principale                                                     |
| --------------------- | ------------------------------------------------------------------ |
| `ReflectionClass`     | Punto d'ingresso per le meta-info di una classe                    |
| `ReflectionMethod`    | Ottiene argomenti, modificatori d'accesso e attributi di un metodo |
| `ReflectionProperty`  | Ottiene tipo, valore di default e attributi di una proprietà       |
| `ReflectionParameter` | Ottiene info sui parametri di metodi/funzioni (type hint, default) |
| `ReflectionFunction`  | Ottiene meta-info di funzioni e closure                            |
| `ReflectionAttribute` | Ottiene nome classe e argomenti di un attributo                    |

### ReflectionClass — informazioni sulla classe

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

$ref->getName();          // nome fully qualified della classe
$ref->getShortName();     // solo il nome della classe
$ref->isInstantiable();   // se è istanziabile
$ref->getConstructor();   // restituisce il costruttore come ReflectionMethod
$ref->getMethods();       // restituisce tutti i metodi come ReflectionMethod[]
$ref->getProperties();    // restituisce tutte le proprietà come ReflectionProperty[]
$ref->getAttributes();    // restituisce gli attributi come ReflectionAttribute[]
```

### ReflectionParameter — ispezionare gli argomenti del costruttore

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

if ($constructor) {
    foreach ($constructor->getParameters() as $param) {
        $param->getName();           // nome del parametro
        $param->getType();           // type hint (ReflectionType)
        $param->isOptional();        // se è opzionale
        $param->isVariadic();        // se è variadic
        $param->getDefaultValue();   // valore di default (se presente)
    }
}
```

## Container di Laravel e Reflection API

L'IoC container di Laravel realizza la constructor injection (risoluzione automatica delle dipendenze) usando la Reflection API. Vediamo il meccanismo alla base di `app()->make(SomeClass::class)` e della dependency injection.

```mermaid theme={null}
sequenceDiagram
    participant App as Codice app
    participant Container as IoC container
    participant Reflection as ReflectionClass
    participant Dep as Classe dipendente

    App->>Container: app()->make(UserController::class)
    Container->>Reflection: new ReflectionClass(UserController::class)
    Reflection-->>Container: Info sul costruttore
    Container->>Reflection: getConstructor()->getParameters()
    Reflection-->>Container: [UserRepository, Cache, ...]
    loop Risolve ciascun argomento
        Container->>Container: make() ricorsivo tramite type hint
        Container->>Dep: new Dep(...)
        Dep-->>Container: Istanza
    end
    Container-->>App: new UserController(repository, cache, ...)
```

### Metodo `build()` del container (semplificato)

Il metodo `build()` reale di `Container.php` è più o meno così.

```php theme={null}
// Illuminate\Container\Container::build() semplificato
public function build($concrete)
{
    // 1. Ispeziona la classe con ReflectionClass
    $reflector = new ReflectionClass($concrete);

    // Le classi non istanziabili (interface, abstract, ecc.) sollevano errore
    if (! $reflector->isInstantiable()) {
        throw new BindingResolutionException("[$concrete] is not instantiable.");
    }

    // 2. Ottiene il costruttore
    $constructor = $reflector->getConstructor();

    // Nessun costruttore → istanzia direttamente
    if (is_null($constructor)) {
        return new $concrete;
    }

    // 3. Ottiene tutti i parametri del costruttore
    $dependencies = $constructor->getParameters();

    // 4. Risolve ricorsivamente ciascun parametro
    $instances = $this->resolveDependencies($dependencies);

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

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

    foreach ($dependencies as $dependency) {
        // Se c'è un type hint, risolve ricorsivamente col container
        $className = Util::getParameterClassName($dependency);

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

    return $results;
}
```

<Info>
  `Util::getParameterClassName()` è una utility che estrae la stringa del tipo dal risultato di `$parameter->getType()`. Fa da wrapper conveniente al `ReflectionNamedType` restituito da `ReflectionParameter::getType()`.
</Info>

## Lettura degli attributi PHP

Da PHP 8.0, tramite la Reflection API puoi ottenere gli attributi applicati a classi, metodi e proprietà. Laravel usa questo meccanismo per gestire gli attributi delle code e di Eloquent.

<Tip>
  Per gli attributi PHP e la loro integrazione in Laravel, consulta anche [Attributi PHP](/it/advanced/php-attributes).
</Tip>

### Pattern base per leggere gli attributi

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

// 1. ottieni gli attributi applicati alla classe
$ref = new ReflectionClass(ProcessOrder::class);
$attrs = $ref->getAttributes(Queue::class); // ottieni solo un attributo specifico

foreach ($attrs as $attr) {
    $instance = $attr->newInstance(); // istanzia la classe attributo
    echo $instance->queue;            // leggi le proprietà dell'attributo
}

// 2. ottieni tutti gli attributi (senza filtro)
$allAttrs = $ref->getAttributes();

foreach ($allAttrs as $attr) {
    echo $attr->getName();       // nome classe attributo (FQCN)
    print_r($attr->getArguments()); // argomenti del costruttore
}
```

### Come Laravel legge gli attributi Queue (semplificato)

```php theme={null}
// semplificato da ReadsQueueAttributes del 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;
    }
}
```

### Leggere gli attributi dei metodi

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

## Utilizzi nello sviluppo di pacchetti

### Verificare le interfacce implementate da una classe

In un pacchetto puoi verificare dinamicamente se una classe implementa una specifica interfaccia.

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

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

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

### Ottenere metadati — registrazione automatica delle rotte via attributi

Pattern per raccogliere e registrare rotte in modo automatico combinando attributi e Reflection.

```php theme={null}
// definizione dell'attributo Route custom
#[\Attribute(\Attribute::TARGET_METHOD)]
class Route
{
    public function __construct(
        public string $method,
        public string $path,
    ) {}
}

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

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

// service provider che registra automaticamente le rotte dagli attributi
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()],
                );
            }
        }
    }
}
```

### Chiamata dinamica di metodo — method injection

Il metodo `call()` di Laravel risolve gli argomenti automaticamente con la Reflection. Esempio di come implementare lo stesso meccanismo in un pacchetto.

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

// esempio d'uso
callWithDependencies([new UserController(), 'index'], app());
```

### Raccogliere i valori di default delle proprietà

Pattern per ottenere via Reflection i valori di default di una classe di configurazione.

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

## Considerazioni sulle performance

La Reflection API riparsa ogni volta le info di classe, quindi ha un costo. Nella produzione è best practice mettere in cache i risultati.

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

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

// esempio d'uso
$ref = ReflectionCache::getClass(UserController::class);
```

<Warning>
  L'OPcache di PHP non memorizza in cache i risultati della Reflection. Se ispezioni molte classi in loop, valuta una cache tua. Nota però che il container di Laravel già riutilizza le istanze di `ReflectionClass` all'interno della stessa richiesta.
</Warning>

## Prossimi passi

<Columns cols={2}>
  <Card title="Attributi PHP" icon="tag" href="/it/advanced/php-attributes">
    Approfondisci gli attributi PHP letti tramite `ReflectionClass::getAttributes()`.
  </Card>

  <Card title="Sviluppo di pacchetti" icon="package" href="/it/advanced/package-development">
    Impara a sviluppare pacchetti Laravel sfruttando la Reflection API.
  </Card>
</Columns>


## Related topics

- [Attributi PHP](/it/advanced/php-attributes.md)
- [Riferimento API - VOICEVOX Core for PHP](/it/packages/voicevox-core-php/api.md)
- [FAQ sulla nuova struttura dell'app da Laravel 11](/it/advanced/app-structure-faq.md)
- [Service Container](/it/service-container.md)
- [PHP FFI](/it/advanced/ffi.md)
