dentelis / php7-attribute-reader
Library for reading php8 attributes from legacy php7 code
Requires
- php: ~7.2
Requires (Dev)
- phpunit/phpunit: ^8.5
This package is auto-updated.
Last update: 2026-03-24 21:39:02 UTC
README
A library that brings PHP 8 attribute syntax to PHP 7.2+. The API mirrors PHP 8's native ReflectionAttribute as closely as possible, making future migration trivial.
Installation
composer require dentelis/php7-attribute-reader
Quick Start
use AttributeReader\AttributeReader; class UserController { #[Route('/api/users', 'GET')] #[Auth('admin')] public function getUsers() {} } $method = new ReflectionMethod(UserController::class, 'getUsers'); $attributes = AttributeReader::getMethodAttributes($method); foreach ($attributes as $attr) { echo $attr->getName(); // FQCN, e.g. "App\Attributes\Route" print_r($attr->getArguments()); // ['/api/users', 'GET'] $instance = $attr->newInstance(); // Route object }
Comparison with PHP 8
// PHP 8 native: $method = new ReflectionMethod(UserController::class, 'getUsers'); $attrs = $method->getAttributes(Route::class); $route = $attrs[0]->newInstance(); // This library (PHP 7.2+): $method = new ReflectionMethod(UserController::class, 'getUsers'); $attrs = AttributeReader::getMethodAttributes($method, Route::class); $route = $attrs[0]->newInstance();
Migration to PHP 8: replace AttributeReader::getMethodAttributes($method, ...) with $method->getAttributes(...).
API Reference
AttributeReader — Static Methods
All methods return Attribute[] and accept optional filtering parameters.
use AttributeReader\AttributeReader; use AttributeReader\Attribute; // Method attributes AttributeReader::getMethodAttributes(ReflectionMethod $method, ?string $name = null, int $flags = 0): array; // Class attributes AttributeReader::getClassAttributes(ReflectionClass $class, ?string $name = null, int $flags = 0): array; // Property attributes AttributeReader::getPropertyAttributes(ReflectionProperty $property, ?string $name = null, int $flags = 0): array; // Function attributes AttributeReader::getFunctionAttributes(ReflectionFunction $function, ?string $name = null, int $flags = 0): array;
Parameters:
$name— filter by FQCN (exact match by default)$flags—0(default) orAttribute::IS_INSTANCEOF(includes subclasses)
Attribute — Returned Object
$attr->getName(): string; // Fully qualified class name $attr->getArguments(): array; // Parsed arguments (positional and/or named) $attr->newInstance(): object; // Instantiates the attribute class $attr->isRepeated(): bool; // True if the same attribute appears more than once
Constants:
Attribute::IS_INSTANCEOF = 2— matchesReflectionAttribute::IS_INSTANCEOF
Features
Filtering
$method = new ReflectionMethod(Controller::class, 'index'); // All attributes $all = AttributeReader::getMethodAttributes($method); // By exact class $routes = AttributeReader::getMethodAttributes($method, Route::class); // By parent class (includes subclasses) $all = AttributeReader::getMethodAttributes($method, BaseAttribute::class, Attribute::IS_INSTANCEOF);
Class Attributes
#[Controller('/api')] #[Auth('admin')] class UserController { } $class = new ReflectionClass(UserController::class); $attrs = AttributeReader::getClassAttributes($class);
Property Attributes
class User { #[Column('email', unique: true)] public $email; } $prop = new ReflectionProperty(User::class, 'email'); $attrs = AttributeReader::getPropertyAttributes($prop);
Named Arguments
#[Route(path: '/users', method: 'POST')] #[Cache(ttl: 3600, enabled: true)] #[Route('/api/users', method: 'POST')] // mixed positional and named
Multiple Attributes
// Separate lines #[Route('/admin')] #[Auth('admin')] public function dashboard() {} // Comma-separated #[Route('/admin'), Auth('admin')] public function dashboard() {}
Repeated Attributes
#[Middleware('auth')] #[Middleware('logging')] public function index() {} $attrs = AttributeReader::getMethodAttributes($method); $attrs[0]->isRepeated(); // true
Expressions in Arguments
Arithmetic, bitwise, and string concatenation with correct operator precedence:
#[Cache(ttl: 60 * 60 * 24)] // 86400 #[Cache(ttl: (2 + 3) * 10)] // 50 #[Route(path: '/api' . '/users')] // '/api/users' #[Config(flags: 1 | 2 | 4)] // 7 #[Cache(ttl: 2 ** 10)] // 1024
Supported operators: +, -, *, /, %, **, ., |, &, ^, ~, <<, >>
Constants in Arguments
Class constants, aliased imports, and global constants:
use App\Config\Limits; use App\Config\Limits as L; #[Cache(ttl: Limits::DEFAULT_TTL)] // resolved via use statement #[Cache(ttl: L::DEFAULT_TTL)] // aliases work too #[Cache(ttl: Limits::DEFAULT_TTL * 2)] // expressions with constants #[Cache(ttl: PHP_INT_SIZE)] // global PHP constants #[Config(name: Limits::APP_NAME . '-prod')]// concatenation with constants
Attribute Name Resolution
Attribute names are automatically resolved to FQCNs using the file's use statements and namespace — no explicit mapping required.
// In the source file: use App\Attributes\Route; #[Route('/users')] // Resolved to "App\Attributes\Route"
Testing
composer test
Requirements
- PHP 7.2 or higher
License
MIT
Credits
Developed by Dim Entelis