Los attributes en PHP 8+ permiten adjuntar metadatos nativos a clases, métodos, propiedades y parámetros. Esta guía muestra cómo definirlos, aplicarlos y leerlos con Reflection, incluyendo ejemplos prácticos.
Introducción
Antes de PHP 8 se usaban docblocks y parsing de comentarios para añadir metadatos (por ejemplo, rutas). Los attributes son nativos: son clases usadas como metadatos mediante sintaxis literal, p. ej. #[Route('/users')].
Prerrequisitos
Necesitas PHP 8.0+ (los attributes son una característica introducida con PHP 8). También conviene familiaridad básica con clases y la API de Reflection para leer atributos en tiempo de ejecución.
Desarrollo
Procedimiento
- Crear la clase que representará el attribute y marcarla con
#[Attribute]. - Aplicar el attribute sobre clases, métodos, propiedades o parámetros según correspondan.
- Leer los atributos en tiempo de ejecución usando Reflection y, si hace falta, instanciarlos.
A continuación hay snippets que ilustran cada paso: definición, uso y lectura por Reflection.
<?php
#[Attribute(Attribute::TARGET_METHOD)]
class Route
{
public function __construct(
public string $path,
public array $methods = ['GET']
) {}
}
Lenguaje del código: PHP (php)
<?php
class UserController
{
#[Route('/users', methods: ['GET'])]
public function index() {}
}
Lenguaje del código: PHP (php)
<?php
$method = new ReflectionMethod(UserController::class, 'index');
$attributes = $method->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
var_dump($instance->path); // '/users'
}
Lenguaje del código: PHP (php)
Atributos nativos
PHP incluye varios attributes útiles. Aquí hay ejemplos prácticos tomados de la sintaxis nativa que aparecen en el lenguaje.
Ejemplo: #[ReturnTypeWillChange] — se usa para compatibilidad de firmas en bibliotecas.
<?php
class MyIterator implements Iterator
{
#[ReturnTypeWillChange]
public function current() {
return 'foo';
}
}
Lenguaje del código: PHP (php)
Ejemplo: #[Deprecated] — marca elementos en desuso y puede incluir un motivo.
<?php
#[Deprecated(reason: 'Use newFunction() instead.')]
function oldFunction() {
return 'legacy';
}
Lenguaje del código: PHP (php)
Ejemplo: #[AllowDynamicProperties] — re-habilita propiedades dinámicas en clases legadas.
<?php
#[AllowDynamicProperties]
class User {}
$user = new User();
$user->name = 'Lukasz'; // funciona
Lenguaje del código: PHP (php)
Ejemplo: #[SensitiveParameter] — oculta valores en trazas y dumps para parámetros sensibles.
<?php
function login(#[SensitiveParameter] string $password) {
throw new Exception('Oops!');
}
login('super-secret-password');
Lenguaje del código: PHP (php)
Ejemplo: #[Override] — asegura que un método realmente sobrescribe uno del padre.
<?php
class Base {
public function greet() {}
}
class Child extends Base {
#[Override]
public function greet() {
echo "Hello!";
}
}
Lenguaje del código: PHP (php)
Ejemplos
Combinar atributos con frameworks o bibliotecas propias suele reducir la necesidad de parsear docblocks y simplifica extractores de metadatos. Un patrón común: definir attributes para rutas, validar parámetros sensibles y marcar API obsoletas.
Ejemplo práctico rápido: definir una ruta y extraerla desde un bootstrap de aplicación para registrar endpoints.
<?php
// Definición ya mostrada arriba: Route
// En bootstrap de la app:
$rc = new ReflectionClass(UserController::class);
foreach ($rc->getMethods() as $method) {
foreach ($method->getAttributes() as $attr) {
$route = $attr->newInstance();
// registrar $route->path y $route->methods en el router
}
}
Lenguaje del código: PHP (php)
Checklist
- Reemplazar parsing de docblocks por classes-attribute cuando sea posible.
- Marcar las classes de attribute con
#[Attribute]y ajustar TARGET_* según uso. - Actualizar extractores para usar Reflection::getAttributes().
- Probar casos de compatibilidad:
#[ReturnTypeWillChange]y#[AllowDynamicProperties]si persisten dependencias legadas. - Marcar parámetros sensibles con
#[SensitiveParameter]para proteger trazas.
Conclusión
Los attributes son una mejora clara frente a los docblocks: son nativos, más seguros y fáciles de consumir por código. Migrar a attributes reduce parsing ad hoc y coloca la metadata junto al código que la usa.
Si estás manteniendo una librería o framework en PHP, prueba a implementar un pequeño atributo y su extractor: la reducción de complejidad suele notarse rápido.

Deja un comentario