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

> Explica cómo funciona la Reflection API de PHP y cómo se aplica en el contenedor IoC de Laravel y en el desarrollo de paquetes.

## Qué es la Reflection API de PHP

La Reflection API de PHP es una funcionalidad nativa que permite obtener e inspeccionar en tiempo de ejecución la metainformación de clases, métodos, propiedades, funciones y parámetros. Puedes saber qué argumentos recibe el constructor de una clase o qué atributos tiene un método sin modificar el código fuente.

Laravel utiliza intensamente la Reflection API dentro de `Illuminate/Container/Container.php` para implementar la resolución automática del contenedor DI, la lectura de atributos de PHP, la inyección de dependencias por método, etc.

## Clases principales

| Clase                 | Uso principal                                                              |
| --------------------- | -------------------------------------------------------------------------- |
| `ReflectionClass`     | Punto de partida para obtener metainformación de la clase.                 |
| `ReflectionMethod`    | Argumentos, modificadores de acceso y atributos de un método.              |
| `ReflectionProperty`  | Tipo, valor por defecto y atributos de una propiedad.                      |
| `ReflectionParameter` | Información de los argumentos de métodos/funciones (type hints, defaults). |
| `ReflectionFunction`  | Metainformación de funciones y closures.                                   |
| `ReflectionAttribute` | Nombre de clase y argumentos de un atributo.                               |

### ReflectionClass — obtener información de la clase

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

$ref->getName();          // Nombre totalmente cualificado
$ref->getShortName();     // Solo el nombre de la clase
$ref->isInstantiable();   // Si es instanciable
$ref->getConstructor();   // Devuelve el constructor como ReflectionMethod
$ref->getMethods();       // Devuelve todos los métodos como ReflectionMethod[]
$ref->getProperties();    // Devuelve todas las propiedades como ReflectionProperty[]
$ref->getAttributes();    // Devuelve los atributos de la clase como ReflectionAttribute[]
```

### ReflectionParameter — inspeccionar los argumentos del constructor

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

if ($constructor) {
    foreach ($constructor->getParameters() as $param) {
        $param->getName();           // Nombre del argumento
        $param->getType();           // Type hint (ReflectionType)
        $param->isOptional();        // Si es opcional
        $param->isVariadic();        // Si es variádico
        $param->getDefaultValue();   // Valor por defecto (si existe)
    }
}
```

## El contenedor de Laravel y la Reflection API

El contenedor IoC de Laravel usa la Reflection API para lograr la inyección por constructor (resolución automática de dependencias). Comprendamos cómo funcionan `app()->make(SomeClass::class)` y la inyección de dependencias.

```mermaid theme={null}
sequenceDiagram
    participant App as Código de la app
    participant Container as Contenedor IoC
    participant Reflection as ReflectionClass
    participant Dep as Clase dependencia

    App->>Container: app()->make(UserController::class)
    Container->>Reflection: new ReflectionClass(UserController::class)
    Reflection-->>Container: Información del constructor
    Container->>Reflection: getConstructor()->getParameters()
    Reflection-->>Container: [UserRepository, Cache, ...]
    loop Resuelve cada argumento
        Container->>Container: make() recursivo según el type hint
        Container->>Dep: new Dep(...)
        Dep-->>Container: Instancia
    end
    Container-->>App: new UserController(repository, cache, ...)
```

### Método `build()` del contenedor (versión simplificada)

El método `build()` real de `Container.php` es aproximadamente así:

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

    // Las clases no instanciables (interfaces, abstractas...) dan error
    if (! $reflector->isInstantiable()) {
        throw new BindingResolutionException("[$concrete] is not instantiable.");
    }

    // 2. Obtener el constructor
    $constructor = $reflector->getConstructor();

    // Sin constructor → instanciar directamente
    if (is_null($constructor)) {
        return new $concrete;
    }

    // 3. Obtener todos los parámetros del constructor
    $dependencies = $constructor->getParameters();

    // 4. Resolver cada parámetro recursivamente
    $instances = $this->resolveDependencies($dependencies);

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

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

    foreach ($dependencies as $dependency) {
        // Si hay type hint, resolver recursivamente a través del contenedor
        $className = Util::getParameterClassName($dependency);

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

    return $results;
}
```

<Info>
  `Util::getParameterClassName()` es una utilidad que extrae el nombre del tipo como cadena a partir del resultado de `$parameter->getType()`. Envuelve el `ReflectionNamedType` de `ReflectionParameter::getType()` para hacerlo más fácil de usar.
</Info>

## Lectura de atributos de PHP

Desde PHP 8.0, la Reflection API permite obtener los atributos aplicados a clases, métodos y propiedades. Laravel usa este mecanismo para procesar sus atributos de cola y de Eloquent.

<Tip>
  Para más información sobre los atributos de PHP y su integración en Laravel, consulta [Atributos de PHP](/es/advanced/php-attributes).
</Tip>

### Patrón básico de lectura de atributos

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

// 1. Obtener los atributos aplicados a la clase
$ref = new ReflectionClass(ProcessOrder::class);
$attrs = $ref->getAttributes(Queue::class); // Solo el atributo indicado

foreach ($attrs as $attr) {
    $instance = $attr->newInstance(); // Instancia la clase de atributo
    echo $instance->queue;            // Lee la propiedad
}

// 2. Todos los atributos (sin filtro)
$allAttrs = $ref->getAttributes();

foreach ($allAttrs as $attr) {
    echo $attr->getName();       // Nombre de clase (FQCN) del atributo
    print_r($attr->getArguments()); // Argumentos del constructor
}
```

### Cómo Laravel lee el atributo Queue (versión simplificada)

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

### Leer atributos de un método

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

## Ejemplos en el desarrollo de paquetes

### Comprobar las interfaces que implementa una clase

En un paquete puedes verificar dinámicamente si una clase implementa una interfaz concreta.

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

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

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

### Obtener metadatos — registrar rutas automáticamente con atributos

Patrón que combina atributos con Reflection para recolectar rutas de forma automática.

```php theme={null}
// Definición del atributo Route
#[\Attribute(\Attribute::TARGET_METHOD)]
class Route
{
    public function __construct(
        public string $method,
        public string $path,
    ) {}
}

// Uso en el controlador
class UserController
{
    #[Route('GET', '/users')]
    public function index() { /* ... */ }

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

// Service provider que registra rutas a partir de los atributos
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()],
                );
            }
        }
    }
}
```

### Invocación dinámica de métodos — method injection

El método `call()` de Laravel resuelve los argumentos automáticamente mediante Reflection. Ejemplo para implementar el mismo mecanismo en un paquete.

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

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

### Recoger los valores por defecto de las propiedades

Patrón para obtener con Reflection los valores por defecto de una clase de configuración.

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

## Consideraciones de rendimiento

La Reflection API tiene coste porque parsea la información de la clase cada vez. En código de producción es buena práctica cachear los resultados.

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

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

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

<Warning>
  OPcache no cachea los resultados de Reflection. Si vas a inspeccionar muchas clases en bucle, plantéate una caché propia. Aun así, el propio contenedor de Laravel reutiliza las instancias de `ReflectionClass` dentro de la misma petición.
</Warning>

## Próximos pasos

<Columns cols={2}>
  <Card title="Atributos de PHP" icon="tag" href="/es/advanced/php-attributes">
    Detalles de los atributos de PHP que se leen con `ReflectionClass::getAttributes()`.
  </Card>

  <Card title="Desarrollo de paquetes" icon="package" href="/es/advanced/package-development">
    Cómo desarrollar paquetes Laravel aprovechando la Reflection API.
  </Card>
</Columns>


## Related topics

- [Atributos de PHP](/es/advanced/php-attributes.md)
- [Referencia de API - VOICEVOX Core for PHP](/es/packages/voicevox-core-php/api.md)
- [FAQ de la nueva estructura de aplicación de Laravel 11 y posteriores](/es/advanced/app-structure-faq.md)
- [PHP FFI](/es/advanced/ffi.md)
- [Google Sheets API for Laravel](/es/packages/laravel-google-sheets/index.md)
